diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..86a26d6 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +ONECLICK_MALL_PROMOTIONS_API_KEY=tu-api-key +ONECLICK_MALL_PROMOTIONS_COMMERCE_CODE=tu-commerce-code +ONECLICK_MALL_PROMOTIONS_CHILD1_COMMERCE_CODE=tu-child-commerce-code-1 +ONECLICK_MALL_PROMOTIONS_CHILD2_COMMERCE_CODE=tu-child-commerce-code-2 diff --git a/.gitignore b/.gitignore index a01c531..4a81aba 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ Test.java build gradle .DS_Store +.env diff --git a/README.md b/README.md index 72d5146..e1f4a52 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,15 @@ mvn clean install ## Ejecución +El flujo `Webpay Oneclick Mall Promociones` usa estas variables de entorno: + +```bash +ONECLICK_MALL_PROMOTIONS_API_KEY=tu-api-key +ONECLICK_MALL_PROMOTIONS_COMMERCE_CODE=tu-commerce-code +ONECLICK_MALL_PROMOTIONS_CHILD1_COMMERCE_CODE=tu-child-commerce-code-1 +ONECLICK_MALL_PROMOTIONS_CHILD2_COMMERCE_CODE=tu-child-commerce-code-2 +``` + Para poder correr el proyecto en modo desarrollo, debes utilizar el siguiente comando en una consola: ```bash diff --git a/pom.xml b/pom.xml index 7141c09..fd9be83 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ com.github.transbankdevelopers transbank-sdk-java - 6.0.0 + 6.1.0 diff --git a/src/main/java/cl/transbank/webpay/example/controllers/BaseController.java b/src/main/java/cl/transbank/webpay/example/controllers/BaseController.java index 2cb4300..7dccba6 100644 --- a/src/main/java/cl/transbank/webpay/example/controllers/BaseController.java +++ b/src/main/java/cl/transbank/webpay/example/controllers/BaseController.java @@ -6,6 +6,8 @@ import com.google.gson.JsonSerializer; import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Random; public abstract class BaseController { @@ -49,4 +51,12 @@ protected String getDisplayableErrorMessage(Exception e) { } return GENERIC_ERROR_MESSAGE; } + + protected static Map navigation(String... entries) { + Map navigation = new LinkedHashMap<>(); + for (int i = 0; i < entries.length; i += 2) { + navigation.put(entries[i], entries[i + 1]); + } + return navigation; + } } diff --git a/src/main/java/cl/transbank/webpay/example/controllers/PromotionsOneclickMallController.java b/src/main/java/cl/transbank/webpay/example/controllers/PromotionsOneclickMallController.java new file mode 100644 index 0000000..fec997c --- /dev/null +++ b/src/main/java/cl/transbank/webpay/example/controllers/PromotionsOneclickMallController.java @@ -0,0 +1,330 @@ +package cl.transbank.webpay.example.controllers; + +import cl.transbank.common.IntegrationType; +import cl.transbank.webpay.common.WebpayOptions; +import cl.transbank.webpay.exception.*; +import cl.transbank.webpay.oneclick.Oneclick; +import cl.transbank.webpay.oneclick.model.MallTransactionCreateDetails; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +@Log4j2 +@Controller +@RequestMapping("/promotions-oneclick-mall") +public class PromotionsOneclickMallController extends BaseController { + + private static final int AUTHORIZED = 0; + private static final String TEMPLATE_FOLDER = "promotions_oneclick_mall"; + private static final String BASE_URL = "/promotions-oneclick-mall"; + private static final String PRODUCT = "Webpay Oneclick Mall Promociones"; + private static final String MODEL_NAVIGATION = "navigation"; + private static final String MODEL_RESPONSE = "response_data"; + private static final String MODEL_RESPONSE_JSON = "response_data_json"; + private static final String REQUEST_DATA_JSON = "request_data_json"; + private static final String REQUEST = "Petición"; + private static final String RESPONSE = "Respuesta"; + + private static final String VIEW_START = TEMPLATE_FOLDER + "/start"; + private static final String VIEW_FINISH = TEMPLATE_FOLDER + "/finish"; + private static final String VIEW_AUTHORIZE = TEMPLATE_FOLDER + "/authorize"; + private static final String VIEW_DELETE = TEMPLATE_FOLDER + "/delete"; + private static final String VIEW_STATUS = TEMPLATE_FOLDER + "/status"; + private static final String VIEW_REFUND = TEMPLATE_FOLDER + "/refund"; + private static final String VIEW_INFO_BIN = TEMPLATE_FOLDER + "/info_bin"; + + private static final String ENV_API_KEY = "ONECLICK_MALL_PROMOTIONS_API_KEY"; + private static final String ENV_COMMERCE_CODE = "ONECLICK_MALL_PROMOTIONS_COMMERCE_CODE"; + private static final String ENV_CHILD1_COMMERCE_CODE = "ONECLICK_MALL_PROMOTIONS_CHILD1_COMMERCE_CODE"; + private static final String ENV_CHILD2_COMMERCE_CODE = "ONECLICK_MALL_PROMOTIONS_CHILD2_COMMERCE_CODE"; + private static final String TBK_USER = "tbkUser"; + private static final String REQUEST_KEY = "request"; + private static final String RESPONSE_KEY = "response"; + private static final String DATA_KEY = "Datos"; + private static final String USERNAME = "username"; + private static final String REQUEST_DATA = "request_data"; + + private static final Map NAV_START = navigation( + REQUEST_KEY, REQUEST, + RESPONSE_KEY, RESPONSE, + "form", "Creación del formulario", + "example", "Ejemplo" + ); + private static final Map NAV_FINISH = navigation( + "data", DATA_KEY, + REQUEST_KEY, REQUEST, + RESPONSE_KEY, RESPONSE, + "authorize", "Autorizar una transacción" + ); + private static final Map NAV_FINISH_RECOVER = navigation("data", DATA_KEY); + private static final Map NAV_FINISH_REJECTED = navigation( + "data", DATA_KEY, + REQUEST_KEY, REQUEST, + RESPONSE_KEY, RESPONSE + ); + private static final Map NAV_AUTHORIZE = navigation( + REQUEST_KEY, REQUEST, + RESPONSE_KEY, RESPONSE, + "done", "Listo" + ); + private static final Map NAV_DELETE = navigation(REQUEST_KEY, REQUEST, RESPONSE_KEY, RESPONSE); + private static final Map NAV_TWO_STEP = navigation(REQUEST_KEY, REQUEST, RESPONSE_KEY, RESPONSE); + private static final Map DOTENV = loadDotenv(); + + @Value("${oneclick.mall.promotions.api-key:}") + private String apiKey; + + @Value("${oneclick.mall.promotions.commerce-code:}") + private String commerceCode; + + @Value("${oneclick.mall.promotions.child1-commerce-code:}") + private String child1CommerceCode; + + @Value("${oneclick.mall.promotions.child2-commerce-code:}") + private String child2CommerceCode; + + @GetMapping({"", "/", "/start"}) + public String start(HttpServletRequest req, Model model) + throws IOException, InscriptionStartException { + addPageMetadata(model, NAV_START, "Iniciar inscripción"); + + String username = "User-" + getRandomNumber(); + String email = "user." + getRandomNumber() + "@example.com"; + String requestUrl = req.getRequestURL().toString(); + String returnUrl = requestUrl.replaceFirst("/start/?$", "").replaceFirst("/$", "") + "/finish"; + + var resp = getInscription().start(username, email, returnUrl); + + Map requestData = Map.of( + USERNAME, username, + "email", email, + "returnUrl", returnUrl + ); + + model.addAttribute(REQUEST_DATA, requestData); + model.addAttribute(REQUEST_DATA_JSON, toJson(requestData)); + model.addAttribute(MODEL_RESPONSE, resp); + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); + + req.getSession().setAttribute(USERNAME, username); + req.getSession().setAttribute("email", email); + + return VIEW_START; + } + + @GetMapping("/finish") + public String finish(HttpServletRequest req, + @RequestParam Map params, + @RequestParam(name = "TBK_TOKEN", required = false) String token, + @RequestParam(name = "TBK_ORDEN_COMPRA", required = false) String ordenCompra, + Model model) + throws IOException, InscriptionFinishException { + addPageMetadata(model, NAV_FINISH, "Finalizar inscripción"); + + if (ordenCompra != null) { + addNavigation(model, NAV_FINISH_RECOVER); + model.addAttribute(REQUEST_DATA_JSON, toJson(params)); + return VIEW_RECOVER_ERROR; + } + + String username = (String) req.getSession().getAttribute(USERNAME); + var resp = getInscription().finish(token); + + model.addAttribute(MODEL_RESPONSE, resp); + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); + + if (resp.getResponseCode() != AUTHORIZED) { + addNavigation(model, NAV_FINISH_REJECTED); + model.addAttribute(REQUEST_DATA_JSON, toJson(params)); + return VIEW_REJECTED_ERROR; + } + + req.getSession().setAttribute(TBK_USER, resp.getTbkUser()); + + model.addAttribute(REQUEST_DATA, Map.of( + USERNAME, username, + TBK_USER, resp.getTbkUser() + )); + model.addAttribute("token", token); + model.addAttribute(USERNAME, username); + model.addAttribute("tbk_user", resp.getTbkUser()); + model.addAttribute("child_commerce_code1", getConfiguredValue(child1CommerceCode, ENV_CHILD1_COMMERCE_CODE)); + model.addAttribute("child_commerce_code2", getConfiguredValue(child2CommerceCode, ENV_CHILD2_COMMERCE_CODE)); + + return VIEW_FINISH; + } + + @GetMapping("/delete") + public String delete(@RequestParam String username, + @RequestParam("tbk_user") String tbkUser, + Model model) + throws IOException, InscriptionDeleteException { + addPageMetadata(model, NAV_DELETE, "Eliminar inscripción"); + getInscription().delete(tbkUser, username); + return VIEW_DELETE; + } + + @GetMapping("/authorize") + public String authorize( + @RequestParam String username, + @RequestParam("tbk_user") String tbkUser, + @RequestParam("child_commerce_code1") String childCode1, + @RequestParam("child_commerce_code2") String childCode2, + @RequestParam("child_commerce_amount1") double amount1, + @RequestParam("child_commerce_amount2") double amount2, + @RequestParam("child_commerce_installments1") int installments1, + @RequestParam("child_commerce_installments2") int installments2, + Model model) + throws IOException, TransactionAuthorizeException { + addPageMetadata(model, NAV_AUTHORIZE, "Autorizar transacción"); + + String buyOrder = "buyOrder_" + getRandomNumber(); + String childBuyOrder1 = "childBuyOrder1_" + getRandomNumber(); + String childBuyOrder2 = "childBuyOrder2_" + getRandomNumber(); + + var details = MallTransactionCreateDetails + .build() + .add(amount1, childCode1, childBuyOrder1, (byte) installments1) + .add(amount2, childCode2, childBuyOrder2, (byte) installments2); + + var resp = getTransaction().authorize(username, tbkUser, buyOrder, details); + model.addAttribute(MODEL_RESPONSE, resp); + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); + return VIEW_AUTHORIZE; + } + + @GetMapping("/status") + public String status(@RequestParam("buy_order") String buyOrder, Model model) + throws IOException, TransactionStatusException { + addPageMetadata(model, NAV_TWO_STEP, "Consultar estado"); + var resp = getTransaction().status(buyOrder); + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); + return VIEW_STATUS; + } + + @GetMapping("/refund") + public String refund(@RequestParam("buy_order") String buyOrder, + @RequestParam("child_buy_order") String childBuyOrder, + @RequestParam("child_commerce_code") String childCommerceCode, + @RequestParam double amount, + Model model) + throws IOException, TransactionRefundException { + addPageMetadata(model, NAV_TWO_STEP, "Reembolso"); + var resp = getTransaction().refund(buyOrder, childCommerceCode, childBuyOrder, amount); + model.addAttribute("buy_order", buyOrder); + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); + return VIEW_REFUND; + } + + @GetMapping("/info-bin") + public String infoBin(@RequestParam("tbk_user") String tbkUser, Model model) + throws IOException, QueryBinException { + addPageMetadata(model, NAV_TWO_STEP, "Consulta servicio de bines"); + var requestData = Map.of(TBK_USER, tbkUser); + var resp = getBinInfo().queryBin(tbkUser); + model.addAttribute(REQUEST_DATA, requestData); + model.addAttribute(REQUEST_DATA_JSON, toJson(requestData)); + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); + return VIEW_INFO_BIN; + } + + @ExceptionHandler(Exception.class) + public String handleException(Exception e, Model model) { + log.error("Error inesperado", e); + model.addAttribute("error", getDisplayableErrorMessage(e)); + return VIEW_ERROR; + } + + private void addPageMetadata(Model model, Map navigation, String label) { + addNavigation(model, navigation); + addBreadcrumbs(model, label, "#"); + } + + private void addNavigation(Model model, Map navigation) { + model.addAttribute(MODEL_NAVIGATION, navigation); + } + + private void addBreadcrumbs(Model model, String label, String url) { + Map breadcrumbs = new LinkedHashMap<>(); + breadcrumbs.put("Inicio", "/"); + breadcrumbs.put(PRODUCT, BASE_URL); + if (label != null) breadcrumbs.put(label, url); + model.addAttribute("product", PRODUCT); + model.addAttribute("base_url", BASE_URL); + model.addAttribute("breadcrumbs", breadcrumbs); + } + + private Oneclick.MallInscription getInscription() { + return new Oneclick.MallInscription(getOptions()); + } + + private Oneclick.MallTransaction getTransaction() { + return new Oneclick.MallTransaction(getOptions()); + } + + private Oneclick.MallBinInfo getBinInfo() { + return new Oneclick.MallBinInfo(getOptions()); + } + + private WebpayOptions getOptions() { + return new WebpayOptions( + getConfiguredValue(commerceCode, ENV_COMMERCE_CODE), + getConfiguredValue(apiKey, ENV_API_KEY), + IntegrationType.TEST + ); + } + + private String getConfiguredValue(String propertyValue, String envName) { + if (propertyValue != null && !propertyValue.isBlank()) { + return propertyValue; + } + + return getEnv(envName); + } + + private String getEnv(String name) { + String value = System.getenv(name); + if (value == null || value.isBlank()) { + value = DOTENV.get(name); + } + if (value == null || value.isBlank()) { + throw new IllegalStateException("La variable de entorno " + name + " es obligatoria."); + } + return value; + } + + private static Map loadDotenv() { + Path path = Path.of(".env"); + if (!Files.exists(path)) { + return Map.of(); + } + + Map values = new HashMap<>(); + try { + for (String line : Files.readAllLines(path)) { + String trimmed = line.trim(); + if (trimmed.isEmpty() || trimmed.startsWith("#") || !trimmed.contains("=")) { + continue; + } + String[] parts = trimmed.split("=", 2); + values.put(parts[0].trim(), parts[1].trim()); + } + } catch (IOException e) { + return Map.of(); + } + return values; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f3fc4f8..21666f8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,6 @@ spring.application.name=transbank-sdk-java-example + +oneclick.mall.promotions.api-key=${ONECLICK_MALL_PROMOTIONS_API_KEY:} +oneclick.mall.promotions.commerce-code=${ONECLICK_MALL_PROMOTIONS_COMMERCE_CODE:} +oneclick.mall.promotions.child1-commerce-code=${ONECLICK_MALL_PROMOTIONS_CHILD1_COMMERCE_CODE:} +oneclick.mall.promotions.child2-commerce-code=${ONECLICK_MALL_PROMOTIONS_CHILD2_COMMERCE_CODE:} diff --git a/src/main/resources/templates/oneclick_mall_deferred/authorize.html b/src/main/resources/templates/oneclick_mall_deferred/authorize.html index 221dc6b..3833576 100644 --- a/src/main/resources/templates/oneclick_mall_deferred/authorize.html +++ b/src/main/resources/templates/oneclick_mall_deferred/authorize.html @@ -70,7 +70,7 @@

¡Casi listo!

Código de comercio (tienda): ¡Casi listo!
Orden de compra (tienda): ¡Casi listo!
Código de autorización (tienda): ¡Casi listo!
Monto a capturar (tienda): -
+
+

Webpay Oneclick Mall Diferido - Capturar transacción diferida

-

Webpay Oneclick Mall Diferido - Capturar transacción diferida

+

+ En este paso debemos capturar la transacción para realmente capturar el + dinero que había sido previamente reservado al hacer la transacción. +

-

- En este paso debemos capturar la transacción para realmente capturar el dinero que había sido - previamente reservado al hacer la transacción. -

+

Paso 1: Petición

-

Paso 1: Petición

+

+ Para capturar una transacción necesitaremos el código de comercio de la + tienda, la orden de compra de la tienda, el código de autorización y el + monto a capturar. Se hace de la siguiente manera: +

-

- Para capturar una transacción necesitaremos el código de comercio de la tienda hija, la orden de compra - de la tienda hija, el código de autorización y el monto a capturar. Se hace de la siguiente manera: -

- -

+    

 var options = new WebpayOptions(
     IntegrationCommerceCodes.ONECLICK_MALL_DEFERRED,
     IntegrationApiKeys.WEBPAY,
@@ -25,58 +25,69 @@ 

Paso 1: Petición

var response = transaction.capture(childCommerceCode, childBuyOrder, authorizationCode, amount);
-

Paso 2: Respuesta

- -

- Una vez creada la transacción, recibirás los siguientes datos de respuesta: -

+

Paso 2: Respuesta

-
+

+ Una vez creada la transacción, recibirás los siguientes datos de + respuesta: +

-

¡Transacción Capturada!

-

- Con la transacción capturada, puedes mostrar al usuario una página de éxito de la transacción, - proporcionándole la confirmación de que el proceso se ha completado con éxito. -

-

- Otras Utilidades: Después de confirmar la transacción, considera las siguientes utilidades - adicionales: -

-

- Reembolso: Evalúa la posibilidad de reversar o anular el pago según ciertas condiciones - comerciales. -

-

- Consulta de Estado: Hasta 7 días después de la transacción, puedes consultar su estado para - obtener más detalles. -

+
-
- - - +

¡Transacción Capturada!

+

+ Con la transacción capturada, puedes mostrar al usuario una página de + éxito de la transacción, proporcionándole la confirmación de que el + proceso se ha completado con éxito. +

+

+ Otras Utilidades: Después de confirmar la transacción, + considera las siguientes utilidades adicionales: +

+

+ Reembolso: Evalúa la posibilidad de reversar o anular el + pago según ciertas condiciones comerciales. +

+

+ Consulta de Estado: Hasta 7 días después de la + transacción, puedes consultar su estado para obtener más detalles. +

-
-
- - -
+ + + + -
- - - CONSULTAR ESTADO - -
-
-
+
+
+ + +
-
+
+ + + CONSULTAR ESTADO + +
+
+ +
diff --git a/src/main/resources/templates/promotions_oneclick_mall/authorize.html b/src/main/resources/templates/promotions_oneclick_mall/authorize.html new file mode 100644 index 0000000..dc72a19 --- /dev/null +++ b/src/main/resources/templates/promotions_oneclick_mall/authorize.html @@ -0,0 +1,35 @@ +
+
+

Webpay Oneclick Mall Promociones - Autorizar pago

+

En este primer paso, procederemos a autorizar una transacción en la tarjeta que ha sido previamente inscrita.

+

Paso 1: Petición

+

Ahora que contamos con el username y el tbkUser, estamos listos para autorizar transacciones.

+
var details = MallTransactionCreateDetails.build()
+    .add(amount1, childCode1, childBuyOrder1, (byte) installments1)
+    .add(amount2, childCode2, childBuyOrder2, (byte) installments2);
+var resp = transaction.authorize(username, tbkUser, buyOrder, details);
+

Paso 2: Respuesta

+

Verifica que el campo responseCode tenga valor 0 y que el campo status sea AUTHORIZED.

+
+

¡Listo!

+

Después de autorizar la transacción, considera las siguientes utilidades adicionales:

+
    +
  • Reembolsar: Puedes reversar o anular el pago según ciertas condiciones comerciales.
  • +
  • Consultar Estado: Hasta 7 días después de realizada la transacción, podrás consultar el estado.
  • +
+
+
+
+
+
+
+
+
+
+ +
+
+
+ CONSULTAR ESTADO +
+
diff --git a/src/main/resources/templates/promotions_oneclick_mall/delete.html b/src/main/resources/templates/promotions_oneclick_mall/delete.html new file mode 100644 index 0000000..30225b2 --- /dev/null +++ b/src/main/resources/templates/promotions_oneclick_mall/delete.html @@ -0,0 +1,12 @@ +
+
+

Webpay Oneclick Mall Promociones - Borrar usuario

+

En este paso fundamental, procederemos a eliminar la inscripción del usuario y su medio de pago.

+

Paso 1: Petición

+

Para llevar a cabo la eliminación, necesitas el "username" y el "tbkUser".

+
inscription.delete(tbkUser, username);
+

Paso 2: Respuesta

+

En caso de éxito, Transbank responderá con un status code 204 (No Content), y el SDK no retornará ningún valor.

+

En el caso de que no se encuentre el "username" o el "tbkUser", el SDK lanzará una excepción del tipo TransbankException.

+
+
diff --git a/src/main/resources/templates/promotions_oneclick_mall/finish.html b/src/main/resources/templates/promotions_oneclick_mall/finish.html new file mode 100644 index 0000000..5dd4f51 --- /dev/null +++ b/src/main/resources/templates/promotions_oneclick_mall/finish.html @@ -0,0 +1,42 @@ +
+
+

Webpay Oneclick Mall Promociones - Finalizar inscripción

+

En esta fase, completaremos el proceso de inscripción, permitiéndonos posteriormente realizar cargos a la tarjeta inscrita.

+

Paso 1: Datos recibidos

+

Después de finalizar el flujo en el formulario de inscripción, recibirás un GET con la siguiente información:

+
{"TBK_TOKEN":""}
+

Paso 2: Petición de autorización

+

Utiliza el token recibido para finalizar la inscripción mediante una nueva llamada a Oneclick.

+
var response = inscription.finish(token);
+

Paso 3: Respuesta

+

Transbank responderá con información crucial. Guarda estos detalles, ya que serán necesarios para autorizar transacciones futuras.

+
+

¡La tarjeta ya está inscrita!

+

Con la inscripción exitosa se pueden autorizar transacciones.

+

Autorizar una transacción

+

Asegúrate de guardar los datos de la respuesta obtenidos durante la inscripción.

+
+

Después de una inscripción exitosa, tienes tres opciones: autorizar un pago, consultar bines o borrar al usuario que se acaba de inscribir.

+
+ + + + +
+

Tienda 1

+
+
+
+
+

Tienda 2

+
+
+
+
+ +
+
+ CONSULTA BINES + BORRAR USUARIO +
+
diff --git a/src/main/resources/templates/promotions_oneclick_mall/info_bin.html b/src/main/resources/templates/promotions_oneclick_mall/info_bin.html new file mode 100644 index 0000000..ca71de9 --- /dev/null +++ b/src/main/resources/templates/promotions_oneclick_mall/info_bin.html @@ -0,0 +1,24 @@ +
+
+

Webpay Oneclick Mall Promociones - Consulta servicio de bines

+

+ Con esta operación puedes consultar el BIN asociado al medio de pago + inscrito usando el valor de tbkUser. Si el comercio no tiene + habilitado este servicio, la respuesta incluirá un error. +

+

Paso 1: Petición

+

+ Para realizar la consulta, necesitarás el tbkUser obtenido al + finalizar la inscripción. +

+
var resp = binInfo.queryBin(tbkUser);
+
+

Paso 2: Respuesta

+

+ Transbank responderá con la información del BIN consultado. +

+
+
+
diff --git a/src/main/resources/templates/promotions_oneclick_mall/refund.html b/src/main/resources/templates/promotions_oneclick_mall/refund.html new file mode 100644 index 0000000..5732feb --- /dev/null +++ b/src/main/resources/templates/promotions_oneclick_mall/refund.html @@ -0,0 +1,39 @@ +
+
+

Webpay Oneclick Mall Promociones - Reembolsar

+

+ En esta etapa, tienes la opción de solicitar el reembolso del monto al + titular de la tarjeta. +

+

Paso 1 - Petición

+

+ Para llevar a cabo el reembolso, necesitas la orden de compra, el código + de comercio(tienda), la orden de compra(tienda) y el monto. +

+

+ En + este link + podrás ver mayor información sobre las condiciones y casos para anular o + reversar transacciones. +

+
var resp = transaction.refund(buyOrder, childCommerceCode, childBuyOrder, amount);
+

Paso 2: Respuesta

+

+ Transbank responderá con el resultado del proceso de reembolso. +

+
+ CONSULTAR ESTADO +
+
diff --git a/src/main/resources/templates/promotions_oneclick_mall/start.html b/src/main/resources/templates/promotions_oneclick_mall/start.html new file mode 100644 index 0000000..95760bf --- /dev/null +++ b/src/main/resources/templates/promotions_oneclick_mall/start.html @@ -0,0 +1,34 @@ +
+
+

Webpay Oneclick Mall Promociones - Creación de Inscripción

+

En esta etapa comienza el proceso de inscripción del medio de pago. Este paso inicial es fundamental para dirigir al Tarjetahabiente al formulario de inscripción.

+

Todas las transacciones en este proyecto de ejemplo son realizadas en ambiente de integración.

+

Paso 1: Petición

+
    +
  1. Comienza por importar la librería Oneclick en tu proyecto.
  2. +
  3. Luego, inicia una inscripción utilizando las funciones proporcionadas mediante el SDK.
  4. +
+
var options = new WebpayOptions(commerceCode, apiKey, IntegrationType.TEST);
+var inscription = new Oneclick.MallInscription(options);
+var resp = inscription.start(username, email, responseUrl);
+

Paso 2: Respuesta

+

Una vez que hayas iniciado la inscripción, aquí encontrarás los datos de respuesta generados por el proceso.

+
+

Paso 3: Creación del formulario

+

Utiliza estos datos de respuesta para redireccionar al usuario al formulario de inscripción del Tarjetahabiente.

+
+

Ejemplo

+

Para llevar a cabo una inscripción en nuestro sistema, primero debemos crearla.

+
+

Para fines de este ejemplo, haremos visible el campo "TBK_TOKEN", el cual es esencial para completar el proceso.

+ Antes de continuar al formulario de Webpay, asegúrate de contar con los datos de las tarjetas de prueba que están en la documentación. +
+
+ Formulario de redirección + + + +
+
+
+
diff --git a/src/main/resources/templates/promotions_oneclick_mall/status.html b/src/main/resources/templates/promotions_oneclick_mall/status.html new file mode 100644 index 0000000..8c1bc45 --- /dev/null +++ b/src/main/resources/templates/promotions_oneclick_mall/status.html @@ -0,0 +1,12 @@ +
+
+

Webpay Oneclick Mall Promociones - Consultar estado de transacción

+

Puedes solicitar el estado de una transacción hasta 7 días después de su realización. No hay límite de solicitudes durante ese período.

+

Paso 1 - Petición:

+

Para realizar la consulta, necesitarás el buyOrder de la transacción de interés.

+
var response = transaction.status(buyOrder);
+

Paso 2: Respuesta

+

Transbank responderá con la siguiente información.

+
+
+