{
  "version": 3,
  "sources": ["/cdn/shop/t/4/assets/dyna-price-core.js?nocache=11918"],
  "sourcesContent": ["// dyna-price-core.js\n// MOXIE: \u00FAnica aritm\u00E9tica y formato de precio B2B, todo en CENTAVOS.\n// base = servicio Dyna (personalizado > gen\u00E9rico > cat\u00E1logo) \u00B7 descuento = /mis-descuentos, una vez.\n// Ver docs/arquitectura/precios-b2b.md.\n\n(function () {\n  'use strict';\n\n  var LOG = '[Dyna price]';\n  var BASE_UNIT_ID = 'UND';\n  // MOXIE: App Proxy de la app Dyna; el Bearer vive en el backend, nunca en el theme.\n  var PROXY_BASE = '/apps/dyna/';\n\n  // MOXIE: separador de miles del formato de moneda de la tienda (1000000 | money), para calzar con Liquid.\n  var thousandsSep = null;\n  function getThousandsSep() {\n    if (thousandsSep !== null) return thousandsSep;\n    thousandsSep = '.';\n    try {\n      var data = document.getElementById('dyna-customer-data');\n      var sample = data ? String(JSON.parse(data.textContent).money_sample || '') : '';\n      var match = sample.match(/^1(\\D)000/);\n      if (match) thousandsSep = match[1];\n    } catch (e) {\n      // sin muestra, formato es-CO\n    }\n    return thousandsSep;\n  }\n\n  // Igual que el filtro `money` de Liquid.\n  /** @param {number} cents */\n  function formatCOP(cents) {\n    var pesos = String(Math.abs(Math.round(cents / 100)));\n    var grouped = pesos.replace(/\\B(?=(\\d{3})+(?!\\d))/g, getThousandsSep());\n    return (cents < 0 ? '-$' : '$') + grouped;\n  }\n\n  /** @param {number} pesos */\n  function pesosToCents(pesos) {\n    return Math.round(Number(pesos) * 100);\n  }\n\n  // SKU Shopify trae la presentaci\u00F3n como sufijo (\"5637-C48\"); Dyna la manda aparte.\n  /**\n   * @param {string} sku\n   * @returns {{ baseSku: string, unitId: string | null }}\n   */\n  function splitShopifySku(sku) {\n    var dashIndex = sku.indexOf('-');\n    if (dashIndex === -1) return { baseSku: sku, unitId: null };\n    return { baseSku: sku.substring(0, dashIndex), unitId: sku.substring(dashIndex + 1) };\n  }\n\n  // Fila del sufijo; si no existe, UND; si tampoco, la m\u00E1s barata.\n  /**\n   * @param {Record<string, { price: number, taxPrice: number }>} unitRows\n   * @param {string | null} preferredUnitId\n   */\n  function pickUnitPrice(unitRows, preferredUnitId) {\n    if (!unitRows) return null;\n    if (preferredUnitId && unitRows[preferredUnitId]) return unitRows[preferredUnitId];\n    if (unitRows[BASE_UNIT_ID]) return unitRows[BASE_UNIT_ID];\n    var lowest = null;\n    for (var unitId in unitRows) {\n      if (lowest === null || unitRows[unitId].taxPrice < lowest.taxPrice) lowest = unitRows[unitId];\n    }\n    return lowest;\n  }\n\n  // Tasa de IVA a partir de la fila del servicio.\n  /**\n   * @param {{ price: number, taxPrice: number, tax?: number } | null} picked\n   * @returns {number | null} porcentaje (ej. 19)\n   */\n  function taxRateFrom(picked) {\n    // MOXIE: la tasa exacta (`tax`) manda; derivarla de tax_price/price arrastra redondeo (19,006%).\n    var exact = picked ? Number(picked.tax) : NaN;\n    if (picked && picked.tax !== undefined && picked.tax !== null && isFinite(exact) && exact >= 0) return exact;\n    if (!picked || !picked.price || !isFinite(picked.price)) return null;\n    var rate = ((picked.taxPrice - picked.price) / picked.price) * 100;\n    if (!isFinite(rate) || rate < 0) return null;\n    return rate;\n  }\n\n  /**\n   * @param {{ baseCents: number, discountPct?: number, taxRate?: number | null }} opts\n   * @returns {{ finalCents: number, ivaCents: number, withIvaCents: number }}\n   */\n  function computePrice(opts) {\n    var baseCents = Number(opts.baseCents) || 0;\n    var pct = Number(opts.discountPct) || 0;\n    var rate = opts.taxRate === null || opts.taxRate === undefined ? NaN : Number(opts.taxRate);\n\n    var finalCents = Math.round(baseCents * (1 - pct / 100));\n    if (!isFinite(rate)) return { finalCents: finalCents, ivaCents: 0, withIvaCents: finalCents };\n\n    // MOXIE: IVA sobre el precio MOSTRADO (pesos enteros): mostrado + IVA = con IVA = mostrado \u00D7 (1 + tasa).\n    var finalPesos = Math.round(finalCents / 100);\n    var ivaPesos = Math.round((finalPesos * rate) / 100);\n\n    return { finalCents: finalPesos * 100, ivaCents: ivaPesos * 100, withIvaCents: (finalPesos + ivaPesos) * 100 };\n  }\n\n  // MOXIE: % acumulados encadenados (custom.descuento \u00D7 /mis-descuentos) \u2192 un solo % con 2 decimales.\n  function combineDiscounts() {\n    var keep = 1;\n    for (var i = 0; i < arguments.length; i++) {\n      var pct = Number(arguments[i]);\n      if (isFinite(pct) && pct > 0) keep *= 1 - Math.min(pct, 100) / 100;\n    }\n    return Math.round((1 - keep) * 10000) / 100;\n  }\n\n  // MOXIE: % de producto (custom.descuento) que la card/PDP expone en data-dyna-product-discount.\n  /** @param {Element | null} el */\n  function getProductDiscount(el) {\n    var host = el && el.closest('[data-dyna-product-discount]');\n    var pct = host ? Number(host.getAttribute('data-dyna-product-discount')) : 0;\n    return isFinite(pct) && pct > 0 ? pct : 0;\n  }\n\n  // Base sin descuento: precio del servicio Dyna si ya se resolvi\u00F3; si no, el cat\u00E1logo.\n  /** @param {Element} el */\n  function getBaseCents(el) {\n    var service = Number(el.getAttribute('data-dyna-service-cents'));\n    if (isFinite(service) && service > 0) return service;\n    return Number(el.getAttribute('data-price-cents') || el.getAttribute('data-dyna-base')) || 0;\n  }\n\n  /**\n   * @param {Element} el\n   * @param {number} cents\n   */\n  function setServiceCents(el, cents) {\n    el.setAttribute('data-dyna-service-cents', String(Math.round(cents)));\n  }\n\n  // Base vigente: la base, o el valor ya descontado. El IVA se calcula sobre esto.\n  /** @param {Element} el */\n  function getEffectiveCents(el) {\n    var eff = Number(el.getAttribute('data-dyna-effective-cents'));\n    if (isFinite(eff) && eff > 0) return eff;\n    return getBaseCents(el);\n  }\n\n  /**\n   * @param {Element} el\n   * @param {number} cents\n   */\n  function setEffectiveCents(el, cents) {\n    el.setAttribute('data-dyna-effective-cents', String(Math.round(cents)));\n  }\n\n  /** @param {Element} el */\n  function getTaxRate(el) {\n    var rate = Number(el.getAttribute('data-dyna-tax-rate'));\n    return isFinite(rate) && el.hasAttribute('data-dyna-tax-rate') ? rate : null;\n  }\n\n  /**\n   * @param {Element} el\n   * @param {number | null} rate\n   */\n  function setTaxRate(el, rate) {\n    if (rate === null) el.removeAttribute('data-dyna-tax-rate');\n    else el.setAttribute('data-dyna-tax-rate', String(rate));\n  }\n\n  // PDP: p\u00EDldoras \"Valor IVA \u00B7 Precio con IVA\". Ac\u00E1 porque se repinta dos veces.\n  /** @param {Element} container */\n  function renderIvaBreakdown(container) {\n    var existing = container.querySelector('.mox-pdp-price__iva-breakdown');\n    var rate = getTaxRate(container);\n\n    if (rate === null) {\n      if (existing) existing.remove();\n      return;\n    }\n\n    var result = computePrice({ baseCents: getEffectiveCents(container), taxRate: rate });\n\n    // MOXIE: si ya existe solo se actualiza el texto \u2014 recrear relanzar\u00EDa el fade.\n    if (existing) {\n      var pills = existing.querySelectorAll('.mox-pdp-price__iva-pill');\n      if (pills.length === 2) {\n        pills[0].textContent = 'Valor IVA: ' + formatCOP(result.ivaCents);\n        pills[1].textContent = 'Precio con IVA: ' + formatCOP(result.withIvaCents);\n        return;\n      }\n      existing.remove();\n    }\n\n    var row = document.createElement('div');\n    row.className = 'mox-pdp-price__iva-breakdown';\n\n    var ivaPill = document.createElement('span');\n    ivaPill.className = 'mox-pdp-price__iva-pill';\n    ivaPill.textContent = 'Valor IVA: ' + formatCOP(result.ivaCents);\n\n    var sep = document.createElement('span');\n    sep.className = 'mox-pdp-price__iva-sep';\n    sep.textContent = '-';\n\n    var totalPill = document.createElement('span');\n    totalPill.className = 'mox-pdp-price__iva-pill mox-pdp-price__iva-pill--total';\n    totalPill.textContent = 'Precio con IVA: ' + formatCOP(result.withIvaCents);\n\n    row.appendChild(ivaPill);\n    row.appendChild(sep);\n    row.appendChild(totalPill);\n    container.appendChild(row);\n  }\n\n  // Informativo: cat\u00E1logo \u2260 servicio; se muestra (y la Function cobra) el servicio.\n  var mismatches = [];\n\n  /**\n   * @param {string} sku\n   * @param {string} unitId\n   * @param {number} baseCents\n   * @param {number} serviceCents\n   */\n  function warnIfMismatch(sku, unitId, baseCents, serviceCents) {\n    if (!baseCents || serviceCents === baseCents) return;\n    mismatches.push({\n      SKU: sku,\n      'Presentaci\u00F3n': unitId,\n      'Cat\u00E1logo Shopify': formatCOP(baseCents),\n      'Servicio Dyna': formatCOP(serviceCents),\n      'Diferencia': formatCOP(serviceCents - baseCents)\n    });\n  }\n\n  function flushMismatches() {\n    if (!mismatches.length) return;\n    console.group(LOG + ' \u2500\u2500 Desfase cat\u00E1logo Shopify vs. servicio Dyna (' + mismatches.length + ') \u2500\u2500');\n    console.warn(LOG, 'Se muestra el servicio; la Function \"Descuento cliente\" cobra ese precio v\u00EDa _dyna_price.');\n    console.table(mismatches);\n    console.groupEnd();\n    mismatches = [];\n  }\n\n  // MOXIE: pages.next de Dyna (absoluto o /shopify/...) se reescribe al App Proxy.\n  /** @param {string} url */\n  function rebaseToProxy(url) {\n    var match = String(url || '').match(/^(?:https?:\\/\\/(?:www\\.)?dynaenterprise\\.com)?\\/shopify\\/([^?#]*)(\\?[^#]*)?/i);\n    return match ? PROXY_BASE + match[1] + (match[2] || '') : url;\n  }\n\n  window.DynaPriceCore = {\n    BASE_UNIT_ID: BASE_UNIT_ID,\n    PROXY_BASE: PROXY_BASE,\n    rebaseToProxy: rebaseToProxy,\n    formatCOP: formatCOP,\n    pesosToCents: pesosToCents,\n    splitShopifySku: splitShopifySku,\n    pickUnitPrice: pickUnitPrice,\n    taxRateFrom: taxRateFrom,\n    computePrice: computePrice,\n    combineDiscounts: combineDiscounts,\n    getProductDiscount: getProductDiscount,\n    getBaseCents: getBaseCents,\n    setServiceCents: setServiceCents,\n    getEffectiveCents: getEffectiveCents,\n    setEffectiveCents: setEffectiveCents,\n    getTaxRate: getTaxRate,\n    setTaxRate: setTaxRate,\n    renderIvaBreakdown: renderIvaBreakdown,\n    warnIfMismatch: warnIfMismatch,\n    flushMismatches: flushMismatches\n  };\n})();\n"],
  "mappings": "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",
  "names": []
}
