Personalización de Estilos de Vault mediante CSSCustomFile

Introducción

Esta documentación te proporcionará información detallada sobre cómo configurar tu archivo CSSCustomFile, que es un archivo JSON que te permitará editar la apariencia de tu Vault de Tarjetas DEUNA. Está dirigida a desarrolladores y comercios interesados en adaptar la apariencia de su bóveda a sus necesidades específicas.

Requisitos Previos

Antes de comenzar, asegúrese de contar con las siguientes informaciones:

  • API keys 🔑
  • Merchant ID 🪪
  • Archivo JSON con estilos que desees configurar 💅

Configuración de Estilos Básicos

Puedes cambiar colores de fondo, textos, ajustar tamaños de fuente y definir márgenes y espaciados. Todo esto de acuerdo a solo un archivo JSON.

Estructura del archivo JSON CSSCustomFile

📘

Recuerda que la propiedad content se utiliza para editar el contenido del texto, mientras que la propiedad style se utiliza para modificar los estilos.

El archivo CSSCustomFile contiene la configuración de estilos del Vault. A continuación, se presenta una descripción detallada de los componentes editables y personalizables, así como un ejemplo de su estructura.

Ejemplo de una estructura JSON válida para la configuración de estilos:

{
  "logoUrl": "https://assets-global.website-files.com/62e806ed6cc7b20ca6dc2b93/64c2aee779502b3676e1024a_Logo%20DEUNA.png",
  "theme": {
    "mainColor": "#FFC0CB",
    "secondaryColor": "#7FFFD4"
  },
  "title": "Pago con tarjeta crédito o débito",
  "header": {
    "content": "Ingresa los datos de tu tarjeta",
    "style": {
      "color": "#333333"
    }
  },
  "header2": {
    "content": "Detalles de Pago",
    "style": {
      "color": "#393E41"
    }
  },
  "nameInput": {
    "content": "Nombre",
    "placeholder": "Escribe Aquí..",
    "style": {
      "color": "#393E41"
    }
  },
  "lastnameInput": {
    "content": "Apellido",
    "placeholder": "Escribe Aquí..",
    "style": {
      "color": "#393E41"
    }
  },
  "hidePoweredBy": false,
  "saveButton": {
    "content": "Pagar",
    "style": {
      "color": "#F6F7EB",
      "backgroundColor": "#7BCCE5"
    }
  },
  "upperTag": {
    "title": {
      "content": "Upper Tag"
    },
    "description": {
      "content": "Aquí puedes agregar un descuento superior"
    }
  },
  "lowerTag": {
    "title": {
      "content": "Lower Tag"
    },
    "description": {
      "content": "Aquí puedes agregar un descuento inferior"
    },
    "style": {
      "color": "#F6F7EB",
      "backgroundColor": "#FFFF00"
    }
  },
  "cardHolderInput": {
    "content": "Nombre en la tarjeta"
  },
  "cardNumberInput": {
    "content": "Número de tarjeta"
  },
  "installmentsInput": {
    "content": "Cuotas"
  },

  "legalMessageText": "Al hacer clic en comprar, aceptar las",
  "showOrderTotal": true,
  "termsAndConditions": {
    "showForGuest": true,
    "showForAuth": true,
    "hideCompanyDisclaimer": false
  }
}

Definición de cada una de las propiedades

PropiedadTipo de ObjetoDescripción
logoUrlStringURL del logotipo que se mostrará en el formulario.
titlestringTítulo del formulario.
headerObjetoObjeto que define el contenido y el estilo del encabezado del formulario.
--contentStringContenido del encabezado.
--styleObjetoObjeto que define el estilo del encabezado, como el color del texto.
upperTagObjeto que define una etiqueta superior opcional en el formulario.
-titleObjetoObjeto que define el título de la etiqueta superior.
--contentStringContenido del título de la etiqueta superior.
-descriptionObjetoObjeto que define la descripción de la etiqueta superior.
--contentStringContenido de la descripción de la etiqueta superior.
cardNumberInputObjeto que define el campo para ingresar el número en la tarjeta.
--contentStringEtiqueta del campo de nombre en la tarjeta.
cardHolderInputObjeto que define el campo para ingresar el nombre de tarjeta.
--contentStringEtiqueta del campo de número de tarjeta.
installmentsInputObjeto que define el campo para seleccionar el número de cuotas.
--contentStringEtiqueta del campo de cuotas.
lowerTagObjeto que define una etiqueta inferior opcional en el formulario.
-titleObjetoObjeto que define el título de la etiqueta inferior.
--contentStringContenido del título de la etiqueta inferior.
-descriptionObjetoObjeto que define la descripción de la etiqueta inferior.
--contentStringContenido de la descripción de la etiqueta inferior.
--styleObjetoObjeto que define el estilo de la etiqueta inferior, como el color del texto y el color de fondo.
legalMessageTextStringTexto legal que se mostrará junto al botón de pagar.
showOrderTotalBooleanBooleano que indica si se debe mostrar el total del pedido en el formulario.
termsAndConditionsObjetoObjeto que define la configuración de los términos y condiciones.
--showForGuestBooleanBooleano que indica si se deben mostrar los términos y condiciones para los usuarios invitados.
--showForAuthBooleanBooleano que indica si se deben mostrar los términos y condiciones para los usuarios autenticados.
hideCompanyDisclaimerBooleanBooleano que indica si se debe ocultar el descargo de responsabilidad de la empresa en los términos y condiciones

Implementación

  1. Configuración Única: Puedes enviar el JSON de estilos personalizados (CSSCustomFile) como parte de la configuración inicial del Vault a través de la API de ConfigurationsV2. Esto aplicará los mismos estilos para todo los enlaces de pago que levantes.
  2. Configuración Dinámica: También puedes crear múltiples JSON de estilos personalizados y pasarlos como query params al momento de levantar el payment link para cada transacción. Esto te brinda la flexibilidad de aplicar diferentes estilos a diferentes transacciones según sea necesario.
curl --location --request POST '{{base_url}}/merchants/{{merchant_id}}/checkout/configurations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IlZOUDlOVGM2SWdxVDhhYVRqYlFnOTRPa2wzZHgtLWZfQjdNdXdTNmYzdmMiLCJ0eXAiOiJKV1QifQ.eyJlbWFpbCI6ImRldmVsb3BlcnNAZ2V0ZHVuYS5jb20iLCJleHAiOjE3MTQyNTc2NjcsImlhdCI6MTcxMzk5ODQ2NywibWVyY2hhbnRfaWQiOm51bGwsIm5ldHdvcmtfaWQiOm51bGwsInJvbGUiOiJzdXBlcmFkbWluIiwic3RvcmVfY29kZSI6bnVsbCwic3ViIjoiMSJ9.ClSQrcThoo6eKQqmbwQgzFduAZkUfhu1kynqMV-eMQZHH0BbCOpu3FQfzyIOkgSOO13LQc9d5C-sV7sriUu7PgDbRedWlnuyAgM0E057tjOXXbpmv1zK-yWz17xpoGaFJMA4lKynxG1PSeTtGek6SBwE0pd8oFehe_-dkK7yh8n5rL2keCoiaURuZnCcQGEb5vfGs84yosvez4J-Nm0kh19_tr7RithSd421EWSSXamsv7QZQB59FXiXLHM4AAPZSxvuc8gt3Mgj4HJe624RRVCcHBZQK7Cgti91JyZ10s95JoGr93vn4T_yxO-8s0wbQVkzYJbO7Q6ay79cuBDsbIKRAkgpZG-jB42-_0Nde6sDAawYFTYdcbMFuDJiK1VbkLXCF6NwS4ASG0L8VCnxWnfmTfiGvl-ZziRhF7FCGNEgwVbiBPuzfZd6sAJlOe_dY5t14IGlm2QzWa-niZxz0M0N3Q3_XeVVhP39hihg2cLUB5sqJj5_EGthI84-CKmU_7e0VRcbJhAKtg8GgpHcppWcV6dy3uj8ABuB_t55PUM_Bd9wbmvYBtesvakLAF9R0zmIRpAn5gfdPIL5Zt6gGheo1Ptn2FmD2UxnVXveg-J0jBRqNGSMCv_OOuHxxBDdL92N6bZqHT6WzLYnxte_ZHEwMrCjvVyEd2kORXPEBI0' \
--header 'Cookie: AWSALB=096u+D212v/57f6ijBB544CvL7oTM8O2rowoCEJ6gS9tXplw/h0/xAOQoY3ZL59jDbvWLN3xSWvfPXd11eqvgQzlAgiQNF7z+URIWNCev3ht2AgTr0S2hKQohmAJ; AWSALBCORS=096u+D212v/57f6ijBB544CvL7oTM8O2rowoCEJ6gS9tXplw/h0/xAOQoY3ZL59jDbvWLN3xSWvfPXd11eqvgQzlAgiQNF7z+URIWNCev3ht2AgTr0S2hKQohmAJ; AWSALB=zKTuhqTmSeuix1M/1pTj94W+dih3P6/vy6u6fBNJEp5norx03QQBWFlZ03Qki8Ni9CiqLXiAuJui4scrCW8MxGQzP8nKfPs9tino8DwWM6SQmxiomLaftNGERg/R; AWSALBCORS=zKTuhqTmSeuix1M/1pTj94W+dih3P6/vy6u6fBNJEp5norx03QQBWFlZ03Qki8Ni9CiqLXiAuJui4scrCW8MxGQzP8nKfPs9tino8DwWM6SQmxiomLaftNGERg/R; AWSALB=uKe+jxTFaHUQinMshpBZFQjfw6M5br+WR7m/aYUYW4/q0EgQyWOXF8FTaBjkTk6w4a1rK5k3K1j0kA1P194XJXg+JrZcP3l54cfzBfzjE24/lqbBmk/JOz7MCHPo; AWSALBCORS=uKe+jxTFaHUQinMshpBZFQjfw6M5br+WR7m/aYUYW4/q0EgQyWOXF8FTaBjkTk6w4a1rK5k3K1j0kA1P194XJXg+JrZcP3l54cfzBfzjE24/lqbBmk/JOz7MCHPo; AWSALB=b5IFrxTGYo8NDVZhW3MgBZojz6G7XWQ1gfTFxB0X4kEtcViPMqzBkiaEy/OSSieHTL33YGRRqFxMf7rb2DAzNg/fWLYHaS5tCLaFT6Az3Y2HAJiF04oCveba/K+M; AWSALBCORS=b5IFrxTGYo8NDVZhW3MgBZojz6G7XWQ1gfTFxB0X4kEtcViPMqzBkiaEy/OSSieHTL33YGRRqFxMf7rb2DAzNg/fWLYHaS5tCLaFT6Az3Y2HAJiF04oCveba/K+M' \
--data '{
    "elements_config": {
        "user_authentication_flow": false,
        "init_with_guest_user": true,
        "theme_config": [
            {
                "id": "{theme_config_id}",
                "name": "theme1",
                "config": "{\n  \"title\": \"¡Dale vida a tu compra!🤩\",\n  \"header\": {\n    \"content\": \"Introduce los detalles de tu tarjeta aquí.\"\n  },\n  \"hidePoweredBy\": true,\n  \"saveButton\": {\n    \"content\": \"Pagar\",\n     \"style\": {\n      \"backgroundColor\": \"#866DE9\",\n      \"color\": \"#ffffff\",\n      \"padding\": \"10px 20px\",\n      \"borderRadius\": \"25px\",\n      \"cursor\": \"pointer\"\n    }\n  },\n  \"termsAndConditions\": {\n    \"showForGuest\": true,\n    \"showForAuth\": false,\n    \"hideCompanyDisclaimer\": true\n  },\n  \"showOrderTotal\": true\n}\n"
            }
        ]
    }
}'
curl --location --request POST '{{base_url}}/merchants/{{merchant_id}}/checkout/configurations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IlZOUDlOVGM2SWdxVDhhYVRqYlFnOTRPa2wzZHgtLWZfQjdNdXdTNmYzdmMiLCJ0eXAiOiJKV1QifQ.eyJlbWFpbCI6ImRldmVsb3BlcnNAZ2V0ZHVuYS5jb20iLCJleHAiOjE3MTQyNTc2NjcsImlhdCI6MTcxMzk5ODQ2NywibWVyY2hhbnRfaWQiOm51bGwsIm5ldHdvcmtfaWQiOm51bGwsInJvbGUiOiJzdXBlcmFkbWluIiwic3RvcmVfY29kZSI6bnVsbCwic3ViIjoiMSJ9.ClSQrcThoo6eKQqmbwQgzFduAZkUfhu1kynqMV-eMQZHH0BbCOpu3FQfzyIOkgSOO13LQc9d5C-sV7sriUu7PgDbRedWlnuyAgM0E057tjOXXbpmv1zK-yWz17xpoGaFJMA4lKynxG1PSeTtGek6SBwE0pd8oFehe_-dkK7yh8n5rL2keCoiaURuZnCcQGEb5vfGs84yosvez4J-Nm0kh19_tr7RithSd421EWSSXamsv7QZQB59FXiXLHM4AAPZSxvuc8gt3Mgj4HJe624RRVCcHBZQK7Cgti91JyZ10s95JoGr93vn4T_yxO-8s0wbQVkzYJbO7Q6ay79cuBDsbIKRAkgpZG-jB42-_0Nde6sDAawYFTYdcbMFuDJiK1VbkLXCF6NwS4ASG0L8VCnxWnfmTfiGvl-ZziRhF7FCGNEgwVbiBPuzfZd6sAJlOe_dY5t14IGlm2QzWa-niZxz0M0N3Q3_XeVVhP39hihg2cLUB5sqJj5_EGthI84-CKmU_7e0VRcbJhAKtg8GgpHcppWcV6dy3uj8ABuB_t55PUM_Bd9wbmvYBtesvakLAF9R0zmIRpAn5gfdPIL5Zt6gGheo1Ptn2FmD2UxnVXveg-J0jBRqNGSMCv_OOuHxxBDdL92N6bZqHT6WzLYnxte_ZHEwMrCjvVyEd2kORXPEBI0' \
--header 'Cookie: AWSALB=096u+D212v/57f6ijBB544CvL7oTM8O2rowoCEJ6gS9tXplw/h0/xAOQoY3ZL59jDbvWLN3xSWvfPXd11eqvgQzlAgiQNF7z+URIWNCev3ht2AgTr0S2hKQohmAJ; AWSALBCORS=096u+D212v/57f6ijBB544CvL7oTM8O2rowoCEJ6gS9tXplw/h0/xAOQoY3ZL59jDbvWLN3xSWvfPXd11eqvgQzlAgiQNF7z+URIWNCev3ht2AgTr0S2hKQohmAJ; AWSALB=zKTuhqTmSeuix1M/1pTj94W+dih3P6/vy6u6fBNJEp5norx03QQBWFlZ03Qki8Ni9CiqLXiAuJui4scrCW8MxGQzP8nKfPs9tino8DwWM6SQmxiomLaftNGERg/R; AWSALBCORS=zKTuhqTmSeuix1M/1pTj94W+dih3P6/vy6u6fBNJEp5norx03QQBWFlZ03Qki8Ni9CiqLXiAuJui4scrCW8MxGQzP8nKfPs9tino8DwWM6SQmxiomLaftNGERg/R; AWSALB=uKe+jxTFaHUQinMshpBZFQjfw6M5br+WR7m/aYUYW4/q0EgQyWOXF8FTaBjkTk6w4a1rK5k3K1j0kA1P194XJXg+JrZcP3l54cfzBfzjE24/lqbBmk/JOz7MCHPo; AWSALBCORS=uKe+jxTFaHUQinMshpBZFQjfw6M5br+WR7m/aYUYW4/q0EgQyWOXF8FTaBjkTk6w4a1rK5k3K1j0kA1P194XJXg+JrZcP3l54cfzBfzjE24/lqbBmk/JOz7MCHPo; AWSALB=b5IFrxTGYo8NDVZhW3MgBZojz6G7XWQ1gfTFxB0X4kEtcViPMqzBkiaEy/OSSieHTL33YGRRqFxMf7rb2DAzNg/fWLYHaS5tCLaFT6Az3Y2HAJiF04oCveba/K+M; AWSALBCORS=b5IFrxTGYo8NDVZhW3MgBZojz6G7XWQ1gfTFxB0X4kEtcViPMqzBkiaEy/OSSieHTL33YGRRqFxMf7rb2DAzNg/fWLYHaS5tCLaFT6Az3Y2HAJiF04oCveba/K+M' \
--data '{
    "elements_config": {
        "user_authentication_flow": false,
        "init_with_guest_user": true,
        "theme_config": [
            {
                "id": "{theme_config_uuid_1}",
                "name": "theme1",
                "config": "{\n  \"title\": \"¡Dale vida a tu compra!🤩\",\n  \"header\": {\n    \"content\": \"Introduce los detalles de tu tarjeta aquí.\"\n  },\n  \"hidePoweredBy\": true,\n  \"saveButton\": {\n    \"content\": \"Pagar\",\n     \"style\": {\n      \"backgroundColor\": \"#866DE9\",\n      \"color\": \"#ffffff\",\n      \"padding\": \"10px 20px\",\n      \"borderRadius\": \"25px\",\n      \"cursor\": \"pointer\"\n    }\n  },\n  \"termsAndConditions\": {\n    \"showForGuest\": true,\n    \"showForAuth\": false,\n    \"hideCompanyDisclaimer\": true\n  },\n  \"showOrderTotal\": true\n}\n"
            },
            {
                "id": "{theme_config_uuid_2}",
                "name": "theme1",
                "config": "{\n  \"title\": \"¡Dale vida a tu compra!👩‍🎤\",\n  \"header\": {\n    \"content\": \"Introduce los detalles de tu tarjeta aquí.\"\n  },\n  \"hidePoweredBy\": true,\n  \"saveButton\": {\n    \"content\": \"Pagar\",\n     \"style\": {\n      \"backgroundColor\": \"#866DE9\",\n      \"color\": \"#ffffff\",\n      \"padding\": \"10px 20px\",\n      \"borderRadius\": \"25px\",\n      \"cursor\": \"pointer\"\n    }\n  },\n  \"termsAndConditions\": {\n    \"showForGuest\": true,\n    \"showForAuth\": false,\n    \"hideCompanyDisclaimer\": true\n  },\n  \"showOrderTotal\": true\n}\n"
            }
        ]
    }
}'
  • Integra tu UUID personalizado a un determinado Vault: Una vez que envías el archivo del css personalizado, el equipo de DEUNA te enviará un identificador. Con este podrás implementar por medio de query params tu css personalizado.

Ejemplo URL: Aquí como luciría tu URL con el customFile añadido:

https://elements.sandbox.deuna.io/click_to_pay?publicApiKey=${apiKey}&firstName=${encodeURIComponent(firstname)}&lastName=${encodeURIComponent(lastname)}&email=${encodeURIComponent(email)}&cssFile=UUID_FROM_DEUNA
https://elements.sandbox.deuna.io/vault?publicApiKey=${apiKey}&firstName=${encodeURIComponent(firstname)}&lastName=${encodeURIComponent(lastname)}&email=${encodeURIComponent(email)}&cssFile=UUID_FROM_DEUNA

Descripción de atributos

AtributoTipoDescripción
cssFileStringUUID generado por DEUNA. Esto identifica el archivo CSSCustomFile

Ejemplo estructura JSON para CSSCustomFile

{
  "logoUrl": "https://assets-global.website-files.com/62e806ed6cc7b20ca6dc2b93/64c2aee779502b3676e1024a_Logo%20DEUNA.png",
  "title": "Pago con tarjeta crédito o débito",
  "header": {
    "content": "Ingresa los datos de tu tarjeta",
    "style": {
      "color": "#333333"
    }
  },
  "header2": {
    "content": "Detalles de Pago",
    "style": {
      "color": "#393E41"
    }
  },
  "nameInput": {
    "content": "Nombre",
    "placeholder": "Escribe Aquí..",
    "style": {
      "color": "#393E41"
    }
  },
  "lastnameInput": {
    "content": "Apellido",
    "placeholder": "Escribe Aquí..",
    "style": {
      "color": "#393E41"
    }
  },
  "hidePoweredBy": false,
  "saveButton": {
    "content": "Pagar",
    "style": {
      "color": "#F6F7EB",
      "backgroundColor": "#7BCCE5"
    }
  },
  "upperTag": {
    "title": {
      "content": "Upper Tag"
    },
    "description": {
      "content": "Aquí puedes agregar un descuento superior"
    }
  },
  "lowerTag": {
    "title": {
      "content": "Lower Tag"
    },
    "description": {
      "content": "Aquí puedes agregar un descuento inferior"
    },
    "style": {
      "color": "#F6F7EB",
      "backgroundColor": "#FFFF00"
    }
  },
  "cardHolderInput": {
    "content": "Nombre en la tarjeta"
  },
  "cardNumberInput": {
    "content": "Número de tarjeta"
  },
  "installmentsInput": {
    "content": "Cuotas"
  },

  "legalMessageText": "Al hacer clic en comprar, aceptar las",
  "showOrderTotal": true,
  "termsAndConditions": {
    "showForGuest": true,
    "showForAuth": true,
    "hideCompanyDisclaimer": false
  }
}

Creación por API

Para facilitar la creación mediante la API, te proporcionamos los endpoints junto con la documentación de referencia que puedes consultar para llevar a cabo el proceso (crear, actualizar, obtener y eliminar temas)

Cambio dinámico del CSSCustomFile

Algunos comercios requieren poder cambiar el custom CSS dependiendo del bin, franquicia, etc. de la tarjeta que ingrese el usuario. Para esto, widget emite un postMessage event con la información de la tarjeta y puede recibir de regreso un postMessage para que el widget actualize los estilos enviados por medio de este postMessage. Una ejemplo a continuación:

// Recibir el evento de la información de la tarjeta
window.addEventListener('message', (event) => {
   let firstParsedData;
   if (typeof event.data === 'string') {
     firstParsedData = JSON.parse(event.data);
    } else {
     firstParsedData = event.data;
    }

    // La información de la tarjeta viene en el "parsedData" en el campo "metadata"
    /*
        metadata: {
           cardBin: number,
           cardBran: string
        }
    */
    const parsedData = JSON.parse(firstParsedData);

    // Este evento se dispara cuando el usuario escribe los primeros 6 dígitos de su tarjeta
    if (
       parsedData &&
       parsedData.type === "onBinDetected"
     ) {
       iframeRef.current?.contentWindow?.postMessage(
         JSON.stringify({
           type: "setCustomCSS",
           data: getCustomCSS(parsedData)
         }),
        '*'
        );
     } 
});

const cardBrands = {
  Mastercard: '#E94F37',
  Visa: '#04264E'
};

// Ejemplo de función helper de getCustomCSS
export const getCustomCSS = (parsedData: any) => ({
  header: {
    content: 'Datos del Tarjetahabiente',
    style: {
      color: '#393E41'
    }
  },
  header2: {
    content: 'Detalles del Pago',
    style: {
      color: '#393E41'
    }
  },
  nameInput: {
    content: 'Nombre',
    placeholder: 'Escribe aquí..',
    style: {
      color: '#393E41'
    }
  },
  lastnameInput: {
    content: 'Apellido',
    placeholder: 'Escribe aquí..',
    style: {
      color: '#393E41'
    }
  },
  upperTag: {
    title: {
      content: 'Tienes 10% de descuento'
    },
    description: {
      content: `Debido a que tu tarjeta es ${parsedData.data?.metadata?.cardBrand}, tienes descuento`
    },
    style: {
      color: '#F6F7EB',
      backgroundColor: `${(cardBrands as any)[parsedData.data?.metadata?.cardBrand]}`
    }
  },
  hidePoweredBy: true,
  saveButton: {
    content: 'Confirmar',
    style: {
      color: '#F6F7EB',
      backgroundColor: '#393E41'
    }
  },
  logoUrl:'https://upload.wikimedia.org/wikipedia/commons/4/44/Cin%C3%A9polis.svg'
});

Ejemplo de una Customización por CSSCustomFile

Puedes ver en este apartado cómo este CSSCustomFile va a modificar la apariencia de nuestro Vault. Fíjate en las propiedades descritas en este archivo JSON:

{
  "title": "¡Dale vida a tu compra!🤩",
  "header": {
    "content": "Introduce los detalles de tu tarjeta aquí."
  },
  "hidePoweredBy": true,
  "saveButton": {
    "content": "Pagar",
     "styles": {
      "backgroundColor": "#8A2BE2",
      "color": "#ffffff",
      "padding": "10px 20px",
      "borderRadius": "25px",
    }
  },
  "termsAndConditions": {
    "showForGuest": true,
    "showForAuth": false,
    "hideCompanyDisclaimer": true
  },
  "showOrderTotal": true
}
Apariencia pre y post aplicación del CSSCustomFile

Apariencia pre y post aplicación del CSSCustomFile