Skip to content

Commit

Permalink
Mibm 27 (#1)
Browse files Browse the repository at this point in the history
* MIBM-27: Adding some test infrastructure

* MIBM-27: Payment service + testing infrastructure

* MIBM-27: renaming

* MIBM-27: Configuration kick off

* MIBM-27: Configuration kick off step#2

* MIBM-27: repackaging + case class value

* MIBM-27: refactoring application.conf

* MIBM-27: refactoring application.conf step#2

* MIBM-27: Add body to request

* MIBM-27: Unused import

* MIBM-27: Add test for serialise/deserialise

* MIBM-27: Make request to pai-api to start payment getting url response

* MIBM-27: Add `pay-now` template

* MIBM-27: rm println

* MIBM-27: pay-api response extractor

* MIBM-27: Add SessionIdGenerator

* MIBM-27: Remove <p>

* MIBM-27: cosmetics

* MIBM-27: Add error handling in case of pay-api failure

* MIBM-27: Test description change
  • Loading branch information
PasGat authored Aug 20, 2020
1 parent 910d52d commit 3b526e7
Show file tree
Hide file tree
Showing 29 changed files with 535 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.config

import javax.inject.{Inject, Singleton}
import play.api.Configuration
import uk.gov.hmrc.play.bootstrap.config.ServicesConfig
import javax.inject.Singleton
import pureconfig.ConfigSource
import pureconfig.generic.auto._
import uk.gov.hmrc.merchandiseinbaggagefrontend.model.core.URL // Do not remove this

@Singleton
class AppConfig @Inject()(config: Configuration, servicesConfig: ServicesConfig) {
val footerLinkItems: Seq[String] = config.getOptional[Seq[String]]("footerLinkItems").getOrElse(Seq())
class AppConfig() extends PaymentServiceConf {
private val configSource: String => ConfigSource = ConfigSource.default.at _

lazy val footerLinkItems: Seq[String] = configSource("footerLinkItems").loadOrThrow[Seq[String]]
}

trait PaymentServiceConf {
lazy val paymentServiceConf: PaymentServiceConfiguration = ConfigSource.default.at("payment").loadOrThrow[PaymentServiceConfiguration]
import paymentServiceConf._
lazy val paymentBaseUri = s"$protocol://$host:$port/"
}

case class PaymentServiceConfiguration(protocol: String, port: Int, host: String, url: URL)
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.config

import javax.inject.{Inject, Singleton}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.controllers

import javax.inject.{Inject, Singleton}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.controllers

import javax.inject.{Inject, Singleton}
import play.api.mvc._
import uk.gov.hmrc.http.HttpClient
import uk.gov.hmrc.merchandiseinbaggagefrontend.config.{AppConfig, ErrorHandler}
import uk.gov.hmrc.merchandiseinbaggagefrontend.model.api._
import uk.gov.hmrc.merchandiseinbaggagefrontend.service.PaymentService
import uk.gov.hmrc.merchandiseinbaggagefrontend.views.html.PaymentPage
import uk.gov.hmrc.play.bootstrap.frontend.controller.FrontendController

import scala.concurrent.{ExecutionContext, Future}

@Singleton
class PaymentController @Inject()(
mcc: MessagesControllerComponents,
paymentPage: PaymentPage,
httpClient: HttpClient)(implicit val ec: ExecutionContext, appConfig: AppConfig, errorHandler: ErrorHandler)
extends FrontendController(mcc) with PaymentService {

val onPageLoad: Action[AnyContent] = Action.async { implicit request =>
Future.successful(Ok(paymentPage()))
}

def onSubmit(): Action[AnyContent] = Action.async { implicit request =>
//TODO hard coded data for now
val body = PayApitRequest(
MibReference("MIBI1234567890"),
AmountInPence(1),
AmountInPence(2),
AmountInPence(3),
TraderDetails("Trader Inc, 239 Old Street, Berlin, Germany, EC1V 9EY"),
MerchandiseDetails("Parts and technical crew for the forest moon")
)
makePayment(httpClient, body).map(response => Ok(response.body))
.recoverWith {
case _: Throwable => Future.successful(InternalServerError(errorHandler.internalServerErrorTemplate))
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.model.api

import play.api.libs.json.{Format, Json}
import uk.gov.hmrc.merchandiseinbaggagefrontend.model.core.URL
import uk.gov.hmrc.merchandiseinbaggagefrontend.utils.ValueClassFormat

case class JourneyId(value: String)
object JourneyId {
implicit val format: Format[JourneyId] = ValueClassFormat.format(value => JourneyId.apply(value))(_.value)
}

case class PayApiResponse(journeyId: JourneyId, nextUrl: URL)

object PayApiResponse {
implicit val format: Format[PayApiResponse] = Json.format[PayApiResponse]
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.model.api

import play.api.libs.json.{Format, Json}
import uk.gov.hmrc.merchandiseinbaggagefrontend.utils.ValueClassFormat


case class MibReference(value: String)
object MibReference {
implicit val format: Format[MibReference] = ValueClassFormat.format(value => MibReference.apply(value))(_.value)
}

case class AmountInPence(value: Long)
object AmountInPence {
implicit val format: Format[AmountInPence] = ValueClassFormat.formatDouble(value => AmountInPence.apply(value))(_.value)
}

case class TraderDetails(value: String)
object TraderDetails {
implicit val format: Format[TraderDetails] = ValueClassFormat.format(value => TraderDetails.apply(value))(_.value)
}

case class MerchandiseDetails(value: String)
object MerchandiseDetails {
implicit val format: Format[MerchandiseDetails] = ValueClassFormat.format(value => MerchandiseDetails.apply(value))(_.value)
}

case class PayApitRequest(mibReference: MibReference, amountInPence: AmountInPence, vatAmountInPence: AmountInPence,
dutyAmountInPence: AmountInPence, traderDetails: TraderDetails, merchandiseDetails: MerchandiseDetails)
object PayApitRequest {
implicit val format: Format[PayApitRequest] = Json.format[PayApitRequest]
}
14 changes: 14 additions & 0 deletions app/uk/gov/hmrc/merchandiseinbaggagefrontend/model/core/URL.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.model.core

import play.api.libs.json.Format
import uk.gov.hmrc.merchandiseinbaggagefrontend.utils.ValueClassFormat

case class URL(value: String) extends AnyVal
object URL {
implicit val format: Format[URL] = ValueClassFormat.format(value => URL.apply(value))(_.value)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.service

import play.api.libs.json.Json
import uk.gov.hmrc.http.{HeaderCarrier, HttpClient, HttpResponse}
import uk.gov.hmrc.merchandiseinbaggagefrontend.config.PaymentServiceConf
import uk.gov.hmrc.merchandiseinbaggagefrontend.model.api.{PayApiResponse, PayApitRequest}
import uk.gov.hmrc.merchandiseinbaggagefrontend.utils.SessionIdGenerator

import scala.concurrent.{ExecutionContext, Future}

trait PaymentService extends PaymentServiceConf with SessionIdGenerator {

def makePayment(httpClient: HttpClient, requestBody: PayApitRequest)(implicit hc: HeaderCarrier, ec: ExecutionContext): Future[HttpResponse] = {
httpClient.POST(s"$paymentBaseUri${paymentServiceConf.url.value}", Json.toJson(requestBody), addSessionId(hc).headers)
}

protected def extractUrl(response: HttpResponse): PayApiResponse =
Json.parse(response.body).as[PayApiResponse]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.utils

import java.util.UUID

import uk.gov.hmrc.http.{HeaderCarrier, HeaderNames}

trait SessionIdGenerator {

def addSessionId(headerCarrier: HeaderCarrier): HeaderCarrier =
headerCarrier.withExtraHeaders(HeaderNames.xSessionId -> generateSessionId)

protected def generateSessionId: String = UUID.randomUUID().toString
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.utils

import play.api.libs.json._

object ValueClassFormat {
def format[A: Format](fromStringToA: String => A)(fromAToString: A => String) =
Format[A](
Reads[A] {
case JsString(str) => JsSuccess(fromStringToA(str))
case unknown => JsError(s"JsString value expected, got: $unknown")
},
Writes[A](a => JsString(fromAToString(a)))
)

def formatDouble[A: Format](fromNumberToA: Long => A)(fromAToLong: A => Long) =
Format[A](
Reads[A] {
case JsNumber(n) => JsSuccess(fromNumberToA(n.toLong))
case unknown => JsError(s"JsString value expected, got: $unknown")
},
Writes[A](a => JsNumber(fromAToLong(a)))
)
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
@*
* Copyright 2020 HM Revenue & Customs
*
*@

@import uk.gov.hmrc.merchandiseinbaggagefrontend.config.AppConfig

@this(layout: Layout)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright 2020 HM Revenue & Customs
*
*/

package uk.gov.hmrc.merchandiseinbaggagefrontend.views

import play.api.i18n.Messages
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
@*
* Copyright 2020 HM Revenue & Customs
*
*@

@this()

@(headBlock: Option[Html] = None)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
@*
* Copyright 2020 HM Revenue & Customs
*
*@

@import uk.gov.hmrc.merchandiseinbaggagefrontend.config.AppConfig

@this(layout: Layout)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
@*
* Copyright 2020 HM Revenue & Customs
*
*@

@import uk.gov.hmrc.merchandiseinbaggagefrontend.config.AppConfig
@import uk.gov.hmrc.merchandiseinbaggagefrontend.views.FooterLinks
@import uk.gov.hmrc.govukfrontend.views.Layouts
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@*
* Copyright 2020 HM Revenue & Customs
*
*@

@import uk.gov.hmrc.merchandiseinbaggagefrontend.config.AppConfig
@import uk.gov.hmrc.merchandiseinbaggagefrontend.controllers.routes._

@this(layout: Layout, button: components.button)

@()(implicit request: Request[_], messages: Messages, appConfig: AppConfig)

@layout(pageTitle = Some("merchandise-in-baggage-frontend")) {
<h1 class="govuk-heading-xl">merchandise-in-baggage-frontend payment</h1>

@button(messages("payment.button"), href = Some(PaymentController.onSubmit().url), classes = Some("govuk-button"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@*
* Copyright 2020 HM Revenue & Customs
*
*@

@this(govukButton: GovukButton)

@(msg: String, href: Option[String] = None, classes: Option[String] = None)(implicit messages: Messages)

@govukButton(Button(content = Text(messages(msg)), href = href, classes = classes.getOrElse("")))
8 changes: 7 additions & 1 deletion conf/app.routes
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,11 @@

-> /govuk-frontend govuk.Routes
-> /hmrc-frontend hmrcfrontend.Routes
GET /hello-world uk.gov.hmrc.merchandiseinbaggagefrontend.controllers.HelloWorldController.helloWorld

GET /assets/*file controllers.Assets.versioned(path = "/public", file: Asset)


GET /hello-world uk.gov.hmrc.merchandiseinbaggagefrontend.controllers.HelloWorldController.helloWorld

GET /payment uk.gov.hmrc.merchandiseinbaggagefrontend.controllers.PaymentController.onPageLoad
GET /process-payment uk.gov.hmrc.merchandiseinbaggagefrontend.controllers.PaymentController.onSubmit()
11 changes: 9 additions & 2 deletions conf/application.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Copyright 2020 HM Revenue & Customs
#

include "frontend.conf"

appName = "merchandise-in-baggage-frontend"
Expand Down Expand Up @@ -48,7 +51,7 @@ microservice {
host = localhost
port = 2003
prefix = play.${appName}.
enabled = true
enabled = false
}
}

Expand All @@ -71,7 +74,7 @@ metrics {
}

auditing {
enabled = true
enabled = false
traceRequests = true
consumer {
baseUri {
Expand All @@ -88,4 +91,8 @@ google-analytics {

footerLinkItems = ["cookies", "privacy", "termsConditions", "govukHelp"]

payment =
{ type = payment-service-configuration, protocol = "http", port = 9057, host = "localhost" , url = "pay-api/mib-frontend/mib/journey/start" }



2 changes: 2 additions & 0 deletions conf/messages
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ footer.termsConditions.text = Terms and conditions
footer.termsConditions.url = /help/terms-and-conditions
footer.govukHelp.text = Help using GOV.UK
footer.govukHelp.url = https://www.gov.uk/help

payment.button = Pay now
6 changes: 3 additions & 3 deletions conf/prod.routes
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Add all the application routes to the app.routes file
-> /merchandise-in-baggage-frontend app.Routes
-> / health.Routes
-> /merchandise-in-baggage-frontend app.Routes
-> / health.Routes

GET /admin/metrics com.kenshoo.play.metrics.MetricsController.metrics
GET /admin/metrics com.kenshoo.play.metrics.MetricsController.metrics
Loading

0 comments on commit 3b526e7

Please sign in to comment.