|
| 1 | +package cl.transbank.webpay.example.controllers; |
| 2 | + |
| 3 | +import cl.transbank.common.IntegrationApiKeys; |
| 4 | +import cl.transbank.common.IntegrationCommerceCodes; |
| 5 | +import cl.transbank.common.IntegrationType; |
| 6 | +import cl.transbank.webpay.common.WebpayOptions; |
| 7 | +import cl.transbank.webpay.exception.*; |
| 8 | +import cl.transbank.webpay.oneclick.Oneclick; |
| 9 | +import cl.transbank.webpay.oneclick.model.MallTransactionCreateDetails; |
| 10 | +import jakarta.servlet.http.HttpServletRequest; |
| 11 | +import lombok.extern.log4j.Log4j2; |
| 12 | +import org.springframework.stereotype.Controller; |
| 13 | +import org.springframework.ui.Model; |
| 14 | +import org.springframework.web.bind.annotation.*; |
| 15 | + |
| 16 | +import java.io.IOException; |
| 17 | +import java.util.LinkedHashMap; |
| 18 | +import java.util.Map; |
| 19 | + |
| 20 | +@Log4j2 |
| 21 | +@Controller |
| 22 | +@RequestMapping("/oneclick-mall") |
| 23 | +public class OneclickMallController extends BaseController { |
| 24 | + |
| 25 | + private static final int AUTHORIZED = 0; |
| 26 | + private static final String TEMPLATE_FOLDER = "oneclick_mall"; |
| 27 | + private static final String BASE_URL = "/oneclick-mall"; |
| 28 | + private static final String PRODUCT = "Webpay Oneclick Mall"; |
| 29 | + private static final String MODEL_NAVIGATION = "navigation"; |
| 30 | + private static final String MODEL_RESPONSE = "response_data"; |
| 31 | + private static final String MODEL_RESPONSE_JSON = "response_data_json"; |
| 32 | + |
| 33 | + private static final String VIEW_START = TEMPLATE_FOLDER + "/start"; |
| 34 | + private static final String VIEW_FINISH = TEMPLATE_FOLDER + "/finish"; |
| 35 | + private static final String VIEW_AUTHORIZE = TEMPLATE_FOLDER + "/authorize"; |
| 36 | + private static final String VIEW_DELETE = TEMPLATE_FOLDER + "/delete"; |
| 37 | + private static final String VIEW_STATUS = TEMPLATE_FOLDER + "/status"; |
| 38 | + private static final String VIEW_REFUND = TEMPLATE_FOLDER + "/refund"; |
| 39 | + private static final String VIEW_ERROR = "error/error_page"; |
| 40 | + |
| 41 | + private static final Map<String, String> NAV_START; |
| 42 | + private static final Map<String, String> NAV_FINISH; |
| 43 | + private static final Map<String, String> NAV_FINISH_RECOVER; |
| 44 | + private static final Map<String, String> NAV_FINISH_REJECTED; |
| 45 | + private static final Map<String, String> NAV_AUTHORIZE; |
| 46 | + private static final Map<String, String> NAV_DELETE; |
| 47 | + private static final Map<String, String> NAV_STATUS; |
| 48 | + private static final Map<String, String> NAV_REFUND; |
| 49 | + |
| 50 | + |
| 51 | + |
| 52 | + |
| 53 | + static { |
| 54 | + NAV_START = new LinkedHashMap<>(); |
| 55 | + NAV_START.put("request", "Petición"); |
| 56 | + NAV_START.put("response", "Respuesta"); |
| 57 | + NAV_START.put("form", "Creación del formulario"); |
| 58 | + NAV_START.put("example", "Ejemplo"); |
| 59 | + |
| 60 | + NAV_FINISH = new LinkedHashMap<>(); |
| 61 | + NAV_FINISH.put("data", "Datos"); |
| 62 | + NAV_FINISH.put("request", "Petición"); |
| 63 | + NAV_FINISH.put("response", "Respuesta"); |
| 64 | + NAV_FINISH.put("authorize", "Autorizar una transacción"); |
| 65 | + |
| 66 | + NAV_FINISH_RECOVER = new LinkedHashMap<>(); |
| 67 | + NAV_FINISH_RECOVER.put("data", "Datos"); |
| 68 | + |
| 69 | + NAV_FINISH_REJECTED = new LinkedHashMap<>(); |
| 70 | + NAV_FINISH_REJECTED.put("data", "Datos"); |
| 71 | + NAV_FINISH_REJECTED.put("request", "Petición"); |
| 72 | + NAV_FINISH_REJECTED.put("response", "Respuesta"); |
| 73 | + |
| 74 | + NAV_AUTHORIZE = new LinkedHashMap<>(); |
| 75 | + NAV_AUTHORIZE.put("request", "Petición"); |
| 76 | + NAV_AUTHORIZE.put("response", "Respuesta"); |
| 77 | + NAV_AUTHORIZE.put("done", "Listo"); |
| 78 | + |
| 79 | + NAV_STATUS = new LinkedHashMap<>(); |
| 80 | + NAV_STATUS.put("request", "Petición"); |
| 81 | + NAV_STATUS.put("response", "Respuesta"); |
| 82 | + |
| 83 | + NAV_DELETE = new LinkedHashMap<>(); |
| 84 | + NAV_DELETE.put("data", "Borrar usuario"); |
| 85 | + |
| 86 | + NAV_REFUND = NAV_STATUS; |
| 87 | + |
| 88 | + } |
| 89 | + |
| 90 | + private final Oneclick.MallInscription inscription; |
| 91 | + private final Oneclick.MallTransaction transaction; |
| 92 | + |
| 93 | + public OneclickMallController() { |
| 94 | + WebpayOptions options = new WebpayOptions( |
| 95 | + IntegrationCommerceCodes.ONECLICK_MALL, |
| 96 | + IntegrationApiKeys.WEBPAY, |
| 97 | + IntegrationType.TEST |
| 98 | + ); |
| 99 | + this.inscription = new Oneclick.MallInscription(options); |
| 100 | + this.transaction = new Oneclick.MallTransaction(options); |
| 101 | + } |
| 102 | + |
| 103 | + private void addBreadcrumbs(Model model, String label, String url) { |
| 104 | + Map<String, String> breadcrumbs = new LinkedHashMap<>(); |
| 105 | + breadcrumbs.put("Inicio", "/"); |
| 106 | + breadcrumbs.put(PRODUCT, BASE_URL + "/start"); |
| 107 | + if (label != null) breadcrumbs.put(label, url); |
| 108 | + model.addAttribute("product", PRODUCT); |
| 109 | + model.addAttribute("breadcrumbs", breadcrumbs); |
| 110 | + } |
| 111 | + |
| 112 | + @GetMapping("/start") |
| 113 | + public String start(HttpServletRequest req, Model model) |
| 114 | + throws IOException, InscriptionStartException { |
| 115 | + model.addAttribute(MODEL_NAVIGATION, NAV_START); |
| 116 | + addBreadcrumbs(model, "Iniciar inscripción", "#"); |
| 117 | + |
| 118 | + String username = "user_" + getRandomNumber(); |
| 119 | + String email = "user." + getRandomNumber() + "@example.com"; |
| 120 | + String returnUrl = req.getRequestURL().toString().replace("start", "finish"); |
| 121 | + |
| 122 | + var resp = inscription.start(username, email, returnUrl); |
| 123 | + |
| 124 | + model.addAttribute("request_data", Map.of( |
| 125 | + "username", username, |
| 126 | + "email", email, |
| 127 | + "returnUrl", returnUrl |
| 128 | + )); |
| 129 | + model.addAttribute("request_data_json", toJson(Map.of( |
| 130 | + "username", username, |
| 131 | + "email", email, |
| 132 | + "returnUrl", returnUrl |
| 133 | + ))); |
| 134 | + model.addAttribute(MODEL_RESPONSE, resp); |
| 135 | + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); |
| 136 | + model.addAttribute("url", resp.getUrlWebpay()); |
| 137 | + model.addAttribute("token", resp.getToken()); |
| 138 | + |
| 139 | + req.getSession().setAttribute("username", username); |
| 140 | + req.getSession().setAttribute("email", email); |
| 141 | + |
| 142 | + return VIEW_START; |
| 143 | + } |
| 144 | + |
| 145 | + @GetMapping("/finish") |
| 146 | + public String finish(HttpServletRequest req, |
| 147 | + @RequestParam Map<String, String> params, |
| 148 | + @RequestParam(name = "TBK_TOKEN", required = false) String token, |
| 149 | + @RequestParam(name = "TBK_ORDEN_COMPRA", required = false) String ordenCompra, |
| 150 | + Model model) |
| 151 | + throws IOException, InscriptionFinishException { |
| 152 | + |
| 153 | + model.addAttribute(MODEL_NAVIGATION, NAV_FINISH); |
| 154 | + addBreadcrumbs(model, "Finalizar inscripción", "#"); |
| 155 | + |
| 156 | + if (ordenCompra != null) { |
| 157 | + model.addAttribute(MODEL_NAVIGATION, NAV_FINISH_RECOVER); |
| 158 | + model.addAttribute("request_data_json", toJson(params)); |
| 159 | + return VIEW_RECOVER_ERROR; |
| 160 | + } |
| 161 | + |
| 162 | + String username = (String) req.getSession().getAttribute("username"); |
| 163 | + |
| 164 | + var resp = inscription.finish(token); |
| 165 | + model.addAttribute(MODEL_RESPONSE, resp); |
| 166 | + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); |
| 167 | + |
| 168 | + if (resp.getResponseCode() != AUTHORIZED) { |
| 169 | + model.addAttribute(MODEL_NAVIGATION, NAV_FINISH_REJECTED); |
| 170 | + model.addAttribute("request_data_json", toJson(params)); |
| 171 | + return VIEW_REJECTED_ERROR; |
| 172 | + } |
| 173 | + |
| 174 | + req.getSession().setAttribute("tbkUser", resp.getTbkUser()); |
| 175 | + |
| 176 | + model.addAttribute("request_data", Map.of( |
| 177 | + "username", username, |
| 178 | + "tbkUser", resp.getTbkUser() |
| 179 | + )); |
| 180 | + |
| 181 | + model.addAttribute("token", token); |
| 182 | + model.addAttribute("username", username); |
| 183 | + model.addAttribute("tbk_user", resp.getTbkUser()); |
| 184 | + |
| 185 | + model.addAttribute("child_commerce_code1", IntegrationCommerceCodes.ONECLICK_MALL_CHILD1); |
| 186 | + model.addAttribute("child_commerce_code2", IntegrationCommerceCodes.ONECLICK_MALL_CHILD2); |
| 187 | + |
| 188 | + return VIEW_FINISH; |
| 189 | + } |
| 190 | + |
| 191 | + @GetMapping("/delete") |
| 192 | + public String delete(@RequestParam String username, |
| 193 | + @RequestParam("tbk_user") String tbkUser, |
| 194 | + Model model) |
| 195 | + throws IOException, InscriptionDeleteException { |
| 196 | + |
| 197 | + model.addAttribute(MODEL_NAVIGATION, NAV_DELETE); |
| 198 | + addBreadcrumbs(model, "Eliminar inscripción", "#"); |
| 199 | + |
| 200 | + inscription.delete(tbkUser, username); |
| 201 | + model.addAttribute("message", "Inscripción eliminada exitosamente."); |
| 202 | + |
| 203 | + return VIEW_DELETE; |
| 204 | + } |
| 205 | + |
| 206 | + @GetMapping("/authorize") |
| 207 | + public String authorize( |
| 208 | + @RequestParam String username, |
| 209 | + @RequestParam("tbk_user") String tbkUser, |
| 210 | + @RequestParam("child_commerce_code1") String childCode1, |
| 211 | + @RequestParam("child_commerce_code2") String childCode2, |
| 212 | + @RequestParam("child_commerce_amount1") double amount1, |
| 213 | + @RequestParam("child_commerce_amount2") double amount2, |
| 214 | + @RequestParam("child_commerce_installments1") int installments1, |
| 215 | + @RequestParam("child_commerce_installments2") int installments2, |
| 216 | + Model model) |
| 217 | + throws IOException, TransactionAuthorizeException { |
| 218 | + |
| 219 | + model.addAttribute(MODEL_NAVIGATION, NAV_AUTHORIZE); |
| 220 | + addBreadcrumbs(model, "Autorizar transacción", "#"); |
| 221 | + |
| 222 | + String buyOrder = "Order" + getRandomNumber(); |
| 223 | + String childBuyOrder1 = "Order1_" + getRandomNumber(); |
| 224 | + String childBuyOrder2 = "Order2_" + getRandomNumber(); |
| 225 | + |
| 226 | + var details = MallTransactionCreateDetails |
| 227 | + .build() |
| 228 | + .add( |
| 229 | + amount1, |
| 230 | + childCode1, |
| 231 | + childBuyOrder1, |
| 232 | + (byte) installments1 |
| 233 | + ) |
| 234 | + .add( |
| 235 | + amount2, |
| 236 | + childCode2, |
| 237 | + childBuyOrder2, |
| 238 | + (byte) installments2 |
| 239 | + ); |
| 240 | + |
| 241 | + var resp = transaction.authorize(username, tbkUser, buyOrder, details); |
| 242 | + |
| 243 | + model.addAttribute(MODEL_RESPONSE, resp); |
| 244 | + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); |
| 245 | + |
| 246 | + return VIEW_AUTHORIZE; |
| 247 | + } |
| 248 | + |
| 249 | + @GetMapping("/status") |
| 250 | + public String status(@RequestParam("buy_order") String buyOrder, Model model) |
| 251 | + throws IOException, TransactionStatusException { |
| 252 | + |
| 253 | + model.addAttribute(MODEL_NAVIGATION, NAV_STATUS); |
| 254 | + addBreadcrumbs(model, "Consultar estado", "#"); |
| 255 | + |
| 256 | + var resp = transaction.status(buyOrder); |
| 257 | + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); |
| 258 | + |
| 259 | + return VIEW_STATUS; |
| 260 | + } |
| 261 | + |
| 262 | + @GetMapping("/refund") |
| 263 | + public String refund(@RequestParam("buy_order") String buyOrder, |
| 264 | + @RequestParam("child_buy_order") String childBuyOrder, |
| 265 | + @RequestParam("child_commerce_code") String childCommerceCode, |
| 266 | + @RequestParam double amount, |
| 267 | + Model model) |
| 268 | + throws IOException, TransactionRefundException { |
| 269 | + model.addAttribute(MODEL_NAVIGATION, NAV_REFUND); |
| 270 | + addBreadcrumbs(model, "Reembolso", "#"); |
| 271 | + |
| 272 | + model.addAttribute("buy_order", buyOrder); |
| 273 | + var resp = transaction.refund(buyOrder, childCommerceCode, childBuyOrder, amount); |
| 274 | + model.addAttribute(MODEL_RESPONSE_JSON, toJson(resp)); |
| 275 | + |
| 276 | + return VIEW_REFUND; |
| 277 | + } |
| 278 | + |
| 279 | + @ExceptionHandler(Exception.class) |
| 280 | + public String handleException(Exception e, Model model) { |
| 281 | + log.error("Error inesperado", e); |
| 282 | + model.addAttribute("error", e.getMessage()); |
| 283 | + return VIEW_ERROR; |
| 284 | + } |
| 285 | +} |
0 commit comments