From c7ee3dbe19634f1429896179ab179a3ad2982f9d Mon Sep 17 00:00:00 2001 From: "Matheus B. Nakaya" Date: Tue, 4 Sep 2018 13:15:07 -0300 Subject: [PATCH] [RELEASE] v1.0.0 (#16) * adds basic settings and basic auth * adds OAuth authentication * adds Moip API error models * adds Moip API exceptions * adds request properties * adds Setup class * adds GsonFactory * adds missing request properties * doc * preparing methods to receive responses * feat(customer): adds customer endpoint * fix(customer): apply fixes to customer creation * feat(customer): adds get customer * feat(order): adds create order endpoint * feat(order): adds get order * feat(payment): adds payment endpoint * feat(customer): adds funding instruments endpoint and list customers * adds resource to cast objects to map and adds validation to Response method * feat(order): adds list orders * feat(order): adds list order payments * feat(payment): adds capture and cancel pre-authorized * feat(refund): adds refund endpoints * test: add missing tests * feat(notification): adds notification preference endpoint * test(notification): adds missing tests * adds resource to convert the JSON to List * feat(webhook): adds webhook resources * refactor: organize instances * fix method access level * fixed untracked files * remove some @Test annotations * test(customer): add missing unit tests to customer * completes customer unit tests * test(order): adds order unit tests * test(payment): adds payment unit tests * test(refund): adds refund unit tests * test(notification): adds notification unit tests * .gitignore * circleCI integration * circleCI * update circleCI test * update gradle * update circleci * test circleci * test circleci * test circleci * test circleci * test circleci * test circleci * update circleci * test circleci * test circleci * test circleci * test circleci * test circleci * update circleci * remove comment * account * feat(account): adds moip account endpoint * test(account): adds tests to get account * APIResources: fix imports * fix typo * Account: fix method isTaxDocument * Account: refactor method checkExistence * resolves codacy issue * feat(connect): adds Moip Connect features * feat(account): get keys * test(connect): connect unit tests * feat(multiorders): create, get * test(multiorder): get tests * fix class imports * refactor: change resources name * fix class imports * refactor multiorder tests * feat(multipayments): create, get, capture and cancel pre-authorized * test(multipayment): add unit tests * test(multiorder): pay multiorder * test(multiorder): pay multiorder * fix class imports * fix codacy issue * feat(bank account): adds create, get, list, delete and update * test(bank account): add feature tests * style: fix spacement * feat(balances): adds get balances * test: get balances * feat(entries): adds get and list * test: entries * feat(transfers): adds create, revert, get and list * test: transfers * fix class imports * feat(escrow): release * test: escrow * chore: bump version to v1.0.0-beta * remove conflicts * feat: adds PayloadFactory resources * refactor: fix connect resources * docs: adds README.md description * release v1.0.0 --- README.md | 334 +++++++++++++++++- build.gradle | 2 +- src/main/java/br/com/moip/Moip.java | 5 +- .../br/com/moip/helpers/PayloadFactory.java | 44 +++ src/main/java/br/com/moip/models/Connect.java | 8 +- .../moip/integration_tests/ConnectTest.java | 2 +- .../moip/integration_tests/CustomerTest.java | 63 ++-- .../br/com/moip/unit_tests/ConnectTest.java | 4 +- 8 files changed, 421 insertions(+), 41 deletions(-) create mode 100644 src/main/java/br/com/moip/helpers/PayloadFactory.java diff --git a/README.md b/README.md index efa9c9a..0e3f0b1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,333 @@ -# moip-sdk-java + - +# Moip Java SDK + +[![CircleCI](https://circleci.com/gh/moip/moip-sdk-java/tree/master.svg?style=svg)](https://circleci.com/gh/moip/moip-sdk-java/tree/master) +[![Codacy Badge](https://api.codacy.com/project/badge/grade/59c15b9d4e35440c8e1d2810c0509836)](https://www.codacy.com/app/rodrigo-saito/moip-sdk-java) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/moip/moip-sdk-java/blob/master/LICENSE) +[![Slack](https://slackin-cqtchmfquq.now.sh/badge.svg)](https://slackin-cqtchmfquq.now.sh/) + +
+ Index + +* [Simple flow](#simple-flow) + * [Setup](#setup) + * [Authentication](#authentication) + * [Environment](#environment) + * [Finally](#finally) + * [Create customer](#create-customer) + * [Create order](#create-order) + * [Create Payment](#create-payment) + * [Other examples](#other-examples) +* [Exceptions treatment](#exceptions-treatment) +* [Moip documentation](#moip-documentation) +* [Getting help](#getting-help) +* [Contributing](#contributing) + +
+ +## Require + +Java `v1.8ˆ` ![java-cup](https://user-images.githubusercontent.com/32847427/37723265-b8441610-2d0c-11e8-8238-ab27df829a13.png) + +## Installing + +### Gradle + +![Maven-central](https://img.shields.io/maven-central/v/br.com.moip/sdk-java.svg) + +Add the fallowing dependency to `build.gradle` in the project: + +```gradle +// https://mvnrepository.com/artifact/br.com.moip/sdk-java +compile group: 'br.com.moip', name: 'sdk-java', version: 'x.y.z' +``` + +### Maven + +![Maven-central](https://img.shields.io/maven-central/v/br.com.moip/sdk-java.svg) + +Add the fallowing dependency to `pom.xml` in the project: + +```xml + + + br.com.moip + sdk-java + x.y.z + +``` + +### Another installation methods +https://mvnrepository.com/artifact/br.com.moip/sdk-java + +## Simple flow + +This step by step will exemplify the integration flow with simple usage examples. + +### 1. Setup +Before making requests to Moip API its necessary create the **Setup** object, defining the environment, the connect timeout, the read timeout and the authentication that will be used. + +#### 1.1 Authentication +There are two ways to authenticate the request, some endpoints require a "highest authorization level", it will depend on the endpoint and type of request. +```java +import br.com.moip.models.Setup; + +Setup setup = new Setup().setAuthentication(auth).setEnvironment(ENVIRONMENT); +``` + +#### By BasicAuth +The following set will generate a hash `Base64` with your Moip account **token** and **key** to authenticate. +```java +import br.com.moip.auth.Authentication; +import br.com.moip.auth.BasicAuth; + +String token = "01010101010101010101010101010101"; +String key = "ABABABABABABABABABABABABABABABABABABABAB"; + +Authentication auth = new BasicAuth(token, key); +``` + +> :bulb: If you don't know how to get your **token** and **key**, click [here](https://conta-sandbox.moip.com.br/configurations/api_credentials) (you must be logged in). + +#### By OAuth +The following set will create an OAuth authentication object. + +> :bulb: Click [here](https://dev.moip.com.br/v2.0/reference#autenticacao-mp) to know how to get your token OAuth. + +```java +import br.com.moip.auth.Authentication; +import br.com.moip.auth.OAuth; + +String oauth = "8833c9eb036543b6b0acd685a76c9ead_v2"; + +Authentication auth = new OAuth(oauth); +``` + +#### 1.2 Environment +We have some environments that you can send your requests. + +##### Sandbox +The test environment. You can use this to simulate all of your business scenarios. + +``` +Setup.Environment.SANDBOX +``` + +##### Production +**_"The environment of truth"_** :eyes:. This is the environment where the real transactions run. + +``` +Setup.Environment.PRODUCTION +``` + +> :bulb: Before going to production, you need to request homologation of your application [here](https://dev.moip.com.br/page/homologacao-api-v2). + +##### Connect +The connect URL must be used only for operations involving another Moip accounts (_request connect permission, generate the account accessToken, refresh account accessToken_). + +> :bulb: If you want to know more about the Moip Connect flow, check [here](https://dev.moip.com.br/docs/app-1) (PT-BR). + +**Sandbox** +``` +Setup.Environment.CONNECT_SANDBOX +``` + +**Production** +``` +Setup.Environment.CONNECT_PRODUCTION +``` + +#### 1.3 Finally +So, your setup must be something like this: +```java +import br.com.moip.models.Setup; + +Setup setup = new Setup().setAuthentication(auth).setEnvironment(Setup.Environment.SANDBOX); +``` + +### 2. Create customer +With the setup created, you can make requests to Moip API. To start the basic e-commerce flow you need to create a customer. After all, it's whom will order your products or services. + +```java +import static br.com.moip.helpers.PayloadFactory.payloadFactory; +import static br.com.moip.helpers.PayloadFactory.value; + +Map taxDocument = payloadFactory( + value("type", "CPF"), + value("number", "10013390023") +); + +Map phone = payloadFactory( + value("countryCode", "55"), + value("areaCode", "11"), + value("number", "22226842") +); + +Map shippingAddress = payloadFactory( + value("city", "Sao Paulo"), + value("district", "Itaim BiBi"), + value("street", "Av. Brigadeiro Faria Lima"), + value("streetNumber", "3064"), + value("state", "SP"), + value("country", "BRA"), + value("zipCode", "01451001") +); + +Map customerRequestBody = payloadFactory( + value("ownId", "customer_own_id"), + value("fullname", "Test Moip da Silva"), + value("email", "test.moip@mail.com"), + value("birthDate", "1980-5-10"), + value("taxDocument", taxDocument), + value("phone", phone), + value("shippingAddress", shippingAddress) +); + +Map responseCreation = Moip.API.customers().create(customerRequestBody, setup); +``` + +> Read more about customer on [API reference](https://dev.moip.com.br/v2.0/reference#clientes-ec). + +### 3. Create order +Customer created! It's buy time! :tada: + +```java +import static br.com.moip.helpers.PayloadFactory.payloadFactory; +import static br.com.moip.helpers.PayloadFactory.value; + +Map subtotals = payloadFactory( + value("shipping", 15000) +); + +Map amount = payloadFactory( + value("currency", "BRL"), + value("subtotals", subtotals) +); + +Map product1 = payloadFactory( + value("product", "Product 1 Description"), + value("category", "TOYS_AND_GAMES"), + value("quantity", 2), + value("detail", "Anakin's Light Saber"), + value("price", 100000000) +); + +Map product2 = payloadFactory( + value("product", "Product 2 Description"), + value("category", "SCIENCE_AND_LABORATORY"), + value("quantity", 5), + value("detail", "Pym particles"), + value("price", 2450000000) +); + +List items = new ArrayList(); +items.add(product1); +items.add(product2); + +Map customer = payloadFactory( + value("id", "CUS-XXOBPZ80QLYP") +); + +Map order = payloadFactory( + value("ownId", "order_own_id"), + value("amount", amount), + value("items", items), + value("customer", customer) +); + +Map responseCreation = Moip.API.orders().create(order, setup); +``` + +> Read more about order on [API reference](https://dev.moip.com.br/v2.0/reference#pedidos-ec). + +### 4. Create Payment +Alright! Do you have all you need? So, lets pay this order. :moneybag: + +```java +import static br.com.moip.helpers.PayloadFactory.payloadFactory; +import static br.com.moip.helpers.PayloadFactory.value; + +Map taxDocument = payloadFactory( + value("type", "CPF"), + value("number", "33333333333") +); + +Map phone = payloadFactory( + value("countryCode", "55"), + value("areaCode", "11"), + value("number", "66778899") +); + +Map holder = payloadFactory( + value("fullname", "Portador Teste Moip"), + value("birthdate", "1988-12-30"), + value("taxDocument", taxDocument), + value("phone", phone) +); + +Map creditCard = payloadFactory( + value("hash", "CREDIT_CARD_HASH"), + value("store", false), + value("holder", holder) +); + +Map fundingInstrument = payloadFactory( + value("method", "CREDIT_CARD"), + value("creditCard", creditCard) +); + +Map payment = payloadFactory( + value("installmentCount", 1), + value("statementDescriptor", "minhaLoja.com"), + value("fundingInstrument", fundingInstrument) +); + +Map newPay = Moip.API.payments().pay(payment, "order_id", setup); +``` + +> Read more about payment on [API reference](https://dev.moip.com.br/v2.0/reference#pagamentos-ec). + +### Other examples +If you want to see other functional examples, check the [Wiki](https://github.com/moip/moip-sdk-java/wiki). + +## Exceptions treatment +| errors | cause | status | +| :---: | :---: | :---: | +| UnautorizedException | to authentication errors | == 401 | +| ValidationException | to validation errors | >= 400 && <= 499 (except 401) | +| UnexpectedException | to unexpected errors | >= 500 | + +> :warning: To catch these errors, use the bellow treatment: + +```java +import br.com.moip.exception.UnauthorizedException; +import br.com.moip.exception.UnexpectedException; +import br.com.moip.exception.ValidationException; + +try { + + Map newPay = Moip.API.payments().pay(payment, "order_id", setup); + +} catch(UnauthorizedException e) { + // StatusCode == 401 +} catch(UnexpectedException e) { + // StatusCode >= 500 +} catch(ValidationException e) { + // StatusCode entre 400 e 499 (exceto 401) +} +``` + +## Moip documentation + +### Docs +To stay up to date about the **Moip Products**, check the [documentation](https://dev.moip.com.br/v2.0/docs). + +### References +Read more about the **Moip APIs** in [API reference](https://dev.moip.com.br/v2.0/reference). + +## Getting help +We offer many ways to contact us, so if you have a question, do not hesitate, talk to us whatever you need. For questions about API or business rules, contact us by [support](https://dev.moip.com.br/v2.0/) or [slack](https://slackin-cqtchmfquq.now.sh/):slack:. But, if you have a question or suggestion about the SDK, feel free to open an **issue** or **pull request**. + +## Contributing +Do you have an enhancement suggest or found something to fix? Go ahead, help us and let your mark on Moip, open **pull requests** and **issues** against this project. If you want to do it, please read the `CONTRIBUTING.md` to be sure everyone follows the same structure and planning of the project. Remember, we :heart: contributions. :rocket: \ No newline at end of file diff --git a/build.gradle b/build.gradle index a5e11df..8b54977 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' group 'br.com.moip' archivesBaseName = "sdk-java" -version '1.0.0-beta' +version '1.0.0' description = "Java SDK for Moip APIs integration" diff --git a/src/main/java/br/com/moip/Moip.java b/src/main/java/br/com/moip/Moip.java index 6f5c942..1ebcafc 100644 --- a/src/main/java/br/com/moip/Moip.java +++ b/src/main/java/br/com/moip/Moip.java @@ -16,9 +16,6 @@ public class Moip { public static final String CONNECT_PRODUCTION_URL = "https://connect.moip.com.br"; - /** - * - */ private static String USER_AGENT; static { @@ -28,7 +25,7 @@ public class Moip { properties.load(inputStream); USER_AGENT = properties.getProperty("userAgent"); - } catch (Exception e) { // verificar tipo de exception + } catch (Exception e) { USER_AGENT = "MoipJavaSDK/UnknownVersion (+https://github.com/moip/moip-sdk-java/)"; } } diff --git a/src/main/java/br/com/moip/helpers/PayloadFactory.java b/src/main/java/br/com/moip/helpers/PayloadFactory.java new file mode 100644 index 0000000..78d5f4e --- /dev/null +++ b/src/main/java/br/com/moip/helpers/PayloadFactory.java @@ -0,0 +1,44 @@ +package br.com.moip.helpers; + +import java.util.AbstractMap; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class PayloadFactory { + + /** + * This method was created to simplify the construction of request payloads. However, the use of this method + * shouldn't be compulsory and you can also use plain old Maps. + * + * @param entries + * {@code Map.Entry} the entries that will describe the request payload. + * + * @return {@code Map} + */ + @SafeVarargs + public static Map payloadFactory(Map.Entry... entries) { + Map map = new HashMap<>(); + + for (Map.Entry entry : entries) + map.put(entry.getKey(), entry.getValue()); + + return Collections.unmodifiableMap(map); + } + + /** + * This is a auxiliary method used to load the {@code Map} returned from {@code payloadFactory}. The usage + * is similar to {@code Map} interaction, but its simplify the dynamic usage of {@code payloadFactory}. + * + * @param key + * {@code String} the attribute key. + * + * @param value + * {@code Object} the attribute value. + * + * @return {@code Map.Entry} + */ + public static Map.Entry value(String key, Object value) { + return new AbstractMap.SimpleImmutableEntry<>(key, value); + } +} diff --git a/src/main/java/br/com/moip/models/Connect.java b/src/main/java/br/com/moip/models/Connect.java index 690f167..72fc839 100644 --- a/src/main/java/br/com/moip/models/Connect.java +++ b/src/main/java/br/com/moip/models/Connect.java @@ -26,10 +26,14 @@ public class Connect { * {@code String array} the array of permissions that you want to request. * Ex: RECEIVE_FUNDS, MANAGE_ACCOUNT_INFO, TRANSFER_FUNDS... * + * @param setup + * {@code Setup} the setup object. + * * @return {@code String} */ - public String buildUrl(String clientId, String redirectUri, String[] scope) { - String url = "https://connect-sandbox.moip.com.br/oauth/authorize"; + public String buildUrl(String clientId, String redirectUri, String[] scope, Setup setup) { + + String url = setup.getEnvironment() + "/oauth/authorize"; url += String.format("?response_type=code&client_id=%s&redirect_uri=%s&scope=", clientId, redirectUri); diff --git a/src/test/java/br/com/moip/integration_tests/ConnectTest.java b/src/test/java/br/com/moip/integration_tests/ConnectTest.java index 3b469f6..49e7819 100644 --- a/src/test/java/br/com/moip/integration_tests/ConnectTest.java +++ b/src/test/java/br/com/moip/integration_tests/ConnectTest.java @@ -18,7 +18,7 @@ public void buildUrlTest() { String[] scope = {"TRANSFER_FUNDS", "RECEIVE_FUNDS"}; - String url = Moip.API.connect().buildUrl("APP-DVLJHW59IKOS", "http://www.exemplo.com.br/retorno", scope); + String url = Moip.API.connect().buildUrl("APP-DVLJHW59IKOS", "http://www.exemplo.com.br/retorno", scope, setup); System.out.println(url); } diff --git a/src/test/java/br/com/moip/integration_tests/CustomerTest.java b/src/test/java/br/com/moip/integration_tests/CustomerTest.java index ccd7820..7bd7e30 100644 --- a/src/test/java/br/com/moip/integration_tests/CustomerTest.java +++ b/src/test/java/br/com/moip/integration_tests/CustomerTest.java @@ -7,6 +7,9 @@ import br.com.moip.exception.ValidationException; import br.com.moip.models.Setup; +import static br.com.moip.helpers.PayloadFactory.payloadFactory; +import static br.com.moip.helpers.PayloadFactory.value; + import java.util.HashMap; import java.util.Map; @@ -19,38 +22,38 @@ public class CustomerTest { private Setup setup = new Setup().setAuthentication(auth).setEnvironment(Setup.Environment.SANDBOX); - private Map customerRequestBody = new HashMap<>(); - - private Map taxDocument = new HashMap<>(); - - private Map phone = new HashMap<>(); - - private Map shippingAddress = new HashMap<>(); - public void createCustomerTest() { - taxDocument.put("type", "CPF"); - taxDocument.put("number", "10013390023"); - - phone.put("countryCode", "55"); - phone.put("areaCode", "11"); - phone.put("number", "22226842"); - - shippingAddress.put("city", "Sao Paulo"); - shippingAddress.put("district", "Itaim BiBi"); - shippingAddress.put("street", "Av. Brigadeiro Faria Lima"); - shippingAddress.put("streetNumber", "3064"); - shippingAddress.put("state", "SP"); - shippingAddress.put("country", "BRA"); - shippingAddress.put("zipCode", "01451001"); - - customerRequestBody.put("ownId", "ffaajjsnoafg4qq1je24"); - customerRequestBody.put("fullname", "Test Moip da Silva"); - customerRequestBody.put("email", "test.moip@mail.com"); - customerRequestBody.put("birthDate", "1980-5-10"); - customerRequestBody.put("taxDocument", taxDocument); - customerRequestBody.put("phone", phone); - customerRequestBody.put("shippingAddress", shippingAddress); + Map taxDocument = payloadFactory( + value("type", "CPF"), + value("number", "10013390023") + ); + + Map phone = payloadFactory( + value("countryCode", "55"), + value("areaCode", "11"), + value("number", "22226842") + ); + + Map shippingAddress = payloadFactory( + value("city", "Sao Paulo"), + value("district", "Itaim BiBi"), + value("street", "Av. Brigadeiro Faria Lima"), + value("streetNumber", "3064"), + value("state", "SP"), + value("country", "BRA"), + value("zipCode", "01451001") + ); + + Map customerRequestBody = payloadFactory( + value("ownId", "amslmfas12431mfpa"), + value("fullname", "Test Moip da Silva"), + value("email", "test.moip@mail.com"), + value("birthDate", "1980-5-10"), + value("taxDocument", taxDocument), + value("phone", phone), + value("shippingAddress", shippingAddress) + ); try { diff --git a/src/test/java/br/com/moip/unit_tests/ConnectTest.java b/src/test/java/br/com/moip/unit_tests/ConnectTest.java index 019b794..f0863f4 100644 --- a/src/test/java/br/com/moip/unit_tests/ConnectTest.java +++ b/src/test/java/br/com/moip/unit_tests/ConnectTest.java @@ -33,9 +33,11 @@ public void initialize() { @Test public void buildUrl() { + this.setup = new Setup().setEnvironment(Setup.Environment.CONNECT_SANDBOX); + String[] scope = {"TRANSFER_FUNDS", "RECEIVE_FUNDS"}; - String url = Moip.API.connect().buildUrl("APP-DVLJHW59IKOS", "http://www.exemplo.com.br/retorno", scope); + String url = Moip.API.connect().buildUrl("APP-DVLJHW59IKOS", "http://www.exemplo.com.br/retorno", scope, setup); assertEquals("https://connect-sandbox.moip.com.br/oauth/authorize?response_type=code&client_id=APP-DVLJHW59IKOS" + "&redirect_uri=http://www.exemplo.com.br/retorno&scope=TRANSFER_FUNDS,RECEIVE_FUNDS", url);