From 3084fccc45c1fa88e9b79b4af3ca63c647f157df Mon Sep 17 00:00:00 2001 From: Vihang Patil Date: Tue, 21 Aug 2018 21:38:36 +0200 Subject: [PATCH] Temporarily added legacy purchase operation without payment --- .../kotlin/org/ostelco/at/jersey/Tests.kt | 40 +++++++++++++++++++ .../kotlin/org/ostelco/at/okhttp/Tests.kt | 30 ++++++++++++-- .../client/api/resources/ProductsResource.kt | 26 +++++++----- .../prime/client/api/store/SubscriberDAO.kt | 3 ++ .../client/api/store/SubscriberDAOImpl.kt | 27 +++++++++++++ 5 files changed, 112 insertions(+), 14 deletions(-) diff --git a/acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt b/acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt index d2f46a436..c09cfe832 100644 --- a/acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt +++ b/acceptance-tests/src/main/kotlin/org/ostelco/at/jersey/Tests.kt @@ -266,6 +266,46 @@ class PurchaseTest { assert(Instant.now().toEpochMilli() - purchaseRecords.last().timestamp < 10_000) { "Missing Purchase Record" } assertEquals(expectedProducts().first(), purchaseRecords.last().product, "Incorrect 'Product' in purchase record") } + + @Test + fun `jersey test - POST products purchase without payment`() { + + val email = "purchase-legacy-${randomInt()}@test.com" + createProfile(name = "Test Legacy Purchase User", email = email) + + val subscriptionStatusBefore: SubscriptionStatus = get { + path = "/subscription/status" + subscriberId = email + } + val balanceBefore = subscriptionStatusBefore.remaining + + val productSku = "1GB_249NOK" + + post { + path = "/products/$productSku" + subscriberId = email + } + + Thread.sleep(100) // wait for 100 ms for balance to be updated in db + + val subscriptionStatusAfter: SubscriptionStatus = get { + path = "/subscription/status" + subscriberId = email + } + val balanceAfter = subscriptionStatusAfter.remaining + + assertEquals(1_000_000_000, balanceAfter - balanceBefore, "Balance did not increased by 1GB after Purchase") + + val purchaseRecords: PurchaseRecordList = get { + path = "/purchases" + subscriberId = email + } + + purchaseRecords.sortBy { it.timestamp } + + assert(Instant.now().toEpochMilli() - purchaseRecords.last().timestamp < 10_000) { "Missing Purchase Record" } + assertEquals(expectedProducts().first(), purchaseRecords.last().product, "Incorrect 'Product' in purchase record") + } } class AnalyticsTest { diff --git a/acceptance-tests/src/main/kotlin/org/ostelco/at/okhttp/Tests.kt b/acceptance-tests/src/main/kotlin/org/ostelco/at/okhttp/Tests.kt index fff2c1e9c..d572624e8 100644 --- a/acceptance-tests/src/main/kotlin/org/ostelco/at/okhttp/Tests.kt +++ b/acceptance-tests/src/main/kotlin/org/ostelco/at/okhttp/Tests.kt @@ -76,8 +76,6 @@ class ProfileTest { class GetSubscriptions { - private val logger by logger() - @Test fun `okhttp test - GET subscriptions`() { @@ -167,8 +165,6 @@ class GetProductsTest { class PurchaseTest { - private val logger by logger() - @Test fun `okhttp test - POST products purchase`() { @@ -196,6 +192,32 @@ class PurchaseTest { assert(Instant.now().toEpochMilli() - purchaseRecords.last().timestamp < 10_000) { "Missing Purchase Record" } assertEquals(expectedProducts().first(), purchaseRecords.last().product, "Incorrect 'Product' in purchase record") } + + @Test + fun `okhttp test - POST products purchase without payment`() { + + val email = "purchase-legacy-${randomInt()}@test.com" + createProfile(name = "Test Legacy Purchase User", email = email) + + val client = clientForSubject(subject = email) + + val balanceBefore = client.subscriptionStatus.remaining + + client.buyProductDeprecated("1GB_249NOK") + + Thread.sleep(200) // wait for 200 ms for balance to be updated in db + + val balanceAfter = client.subscriptionStatus.remaining + + assertEquals(1_000_000_000, balanceAfter - balanceBefore, "Balance did not increased by 1GB after Purchase") + + val purchaseRecords = client.purchaseHistory + + purchaseRecords.sortBy { it.timestamp } + + assert(Instant.now().toEpochMilli() - purchaseRecords.last().timestamp < 10_000) { "Missing Purchase Record" } + assertEquals(expectedProducts().first(), purchaseRecords.last().product, "Incorrect 'Product' in purchase record") + } } class ConsentTest { diff --git a/client-api/src/main/kotlin/org/ostelco/prime/client/api/resources/ProductsResource.kt b/client-api/src/main/kotlin/org/ostelco/prime/client/api/resources/ProductsResource.kt index f0c787ac3..47be01e8d 100644 --- a/client-api/src/main/kotlin/org/ostelco/prime/client/api/resources/ProductsResource.kt +++ b/client-api/src/main/kotlin/org/ostelco/prime/client/api/resources/ProductsResource.kt @@ -38,14 +38,21 @@ class ProductsResource(private val dao: SubscriberDAO) { @POST @Path("{sku}") @Produces("application/json") - fun purchaseProductOld(@Auth token: AccessTokenPrincipal?, - @NotNull - @PathParam("sku") - sku: String, - @QueryParam("sourceId") - sourceId: String?, - @QueryParam("saveCard") - saveCard: Boolean = false): Response = purchaseProduct(token, sku, sourceId, saveCard) + fun purchaseProductWithoutPayment(@Auth token: AccessTokenPrincipal?, + @NotNull + @PathParam("sku") + sku: String): Response { + if (token == null) { + return Response.status(Response.Status.UNAUTHORIZED) + .build() + } + + return dao.purchaseProductWithoutPayment(token.name, sku) + .fold( + { apiError -> Response.status(apiError.status).entity(asJson(apiError.description)) }, + { productInfo -> Response.status(CREATED).entity(productInfo) } + ).build() + } @POST @Path("{sku}/purchase") @@ -66,8 +73,7 @@ class ProductsResource(private val dao: SubscriberDAO) { return dao.purchaseProduct(token.name, sku, sourceId, saveCard) .fold( { apiError -> Response.status(apiError.status).entity(asJson(apiError.description)) }, - { productInfo -> Response.status(CREATED).entity(productInfo)} + { productInfo -> Response.status(CREATED).entity(productInfo) } ).build() - } } diff --git a/client-api/src/main/kotlin/org/ostelco/prime/client/api/store/SubscriberDAO.kt b/client-api/src/main/kotlin/org/ostelco/prime/client/api/store/SubscriberDAO.kt index 326c9fdc3..0975c490d 100644 --- a/client-api/src/main/kotlin/org/ostelco/prime/client/api/store/SubscriberDAO.kt +++ b/client-api/src/main/kotlin/org/ostelco/prime/client/api/store/SubscriberDAO.kt @@ -87,4 +87,7 @@ interface SubscriberDAO { && !appToken.tokenType.isEmpty()) } } + + @Deprecated(message = "use purchaseProduct") + fun purchaseProductWithoutPayment(subscriberId: String, sku: String): Either } diff --git a/client-api/src/main/kotlin/org/ostelco/prime/client/api/store/SubscriberDAOImpl.kt b/client-api/src/main/kotlin/org/ostelco/prime/client/api/store/SubscriberDAOImpl.kt index d31b0ee94..34d933132 100644 --- a/client-api/src/main/kotlin/org/ostelco/prime/client/api/store/SubscriberDAOImpl.kt +++ b/client-api/src/main/kotlin/org/ostelco/prime/client/api/store/SubscriberDAOImpl.kt @@ -26,6 +26,7 @@ import org.ostelco.prime.paymentprocessor.core.ProfileInfo import org.ostelco.prime.paymentprocessor.core.SourceInfo import org.ostelco.prime.storage.ClientDataSource import java.time.Instant +import java.util.* import java.util.concurrent.ConcurrentHashMap /** @@ -186,6 +187,32 @@ class SubscriberDAOImpl(private val storage: ClientDataSource, private val ocsSu } + @Deprecated("use purchaseProduct", ReplaceWith("purchaseProduct")) + override fun purchaseProductWithoutPayment(subscriberId: String, sku: String): Either { + return getProduct(subscriberId, sku) + // If we can't find the product, return not-found + .mapLeft { NotFoundError("Product unavailable") } + .flatMap { product -> + product.sku = sku + val purchaseRecord = PurchaseRecord( + id = UUID.randomUUID().toString(), + product = product, + timestamp = Instant.now().toEpochMilli()) + // Create purchase record + storage.addPurchaseRecord(subscriberId, purchaseRecord) + .mapLeft { storeError -> + logger.error("failed to save purchase record, for subscriberId $subscriberId, sku $sku") + BadGatewayError(storeError.message) + } + // Notify OCS + .flatMap { + //TODO: Handle errors (when it becomes available) + ocsSubscriberService.topup(subscriberId, sku) + Either.right(Unit) + } + } + } + override fun purchaseProduct(subscriberId: String, sku: String, sourceId: String?, saveCard: Boolean): Either { return getProduct(subscriberId, sku) // If we can't find the product, return not-found