function defineStructure() { addColumn("Code"); addColumn("Description"); addColumn("codigoDescricao"); addColumn("descricao"); addColumn("sku"); addColumn("brand"); addColumn("ncmId"); addColumn("categoria"); } function onSync(lastSyncDate) {} var GB_TOKEN_URL = "https://api.grupoboticario.com.br/global/v2/jwt-token/token"; var GB_STRATEGICS_URL = "https://api.grupoboticario.com.br/global/v1/franchising/gb-stores-data/product/classification/strategics"; var DEFAULT_GB_CLIENT_ID = "88ymKwAUNfu06sD85i0RiokCxWGSkFBkx9ytgI5y1ZKxX3OQ"; var DEFAULT_GB_CLIENT_SECRET = "YDFz43qAzL6ApNIKVCxu3dAmS9GWOqJbcc2aPnFDkmEaBXexSpsHGfcItg56i2dE"; function createDataset(fields, constraints, sortFields) { var dataset = DatasetBuilder.newDataset(); dataset.addColumn("Code"); dataset.addColumn("Description"); dataset.addColumn("codigoDescricao"); dataset.addColumn("descricao"); dataset.addColumn("sku"); dataset.addColumn("brand"); dataset.addColumn("ncmId"); dataset.addColumn("categoria"); try { var filtro = parseConstraints(constraints); var clientService = fluigAPI.getAuthorizeClientService(); var data = { companyId: String(getValue("WKCompany") || "1"), serviceCode: "GINSENG APITESTE", endpoint: "/dados_rgb_products", method: "get", timeoutService: "60000", params: {} }; var vo = clientService.invoke(JSON.stringify(data)); var statusHttp = vo ? String(vo.getHttpStatusResult() || "") : ""; var retorno = vo ? String(vo.getResult() || "") : ""; // Fallback: se o servico integrado estiver com endpoint/base incorreto, chama URL direta. if (statusHttp !== "200" || !retorno) { var direct = fetchDirect("https://api.grupoginseng.com.br/dados_rgb_products", 60000); statusHttp = String(direct.status || statusHttp); retorno = direct.body || retorno; } if (!retorno) { addDiagRow(dataset, "Sem retorno da API (HTTP " + statusHttp + ")"); return dataset; } var obj = parseJsonSafe(retorno); if (!obj) { addDiagRow(dataset, "Falha no JSON da API (HTTP " + statusHttp + ")"); return dataset; } var itens = extractItems(obj); if (!itens || !itens.length) { addDiagRow(dataset, "API sem itens (HTTP " + statusHttp + ")"); return dataset; } var searchNorm = normalize(filtro.search); var maxRows = filtro.maxRows; var categoryMap = null; var categoryDiag = ""; for (var i = 0; i < itens.length; i++) { var item = itens[i] || {}; if (item.discontinued === true) { continue; } if (item.purchaseBlocked === true) { continue; } var code = trim(item.sku); var desc = trim(item.description); var codigoDescricao = code + " - " + desc; var brand = trim(item.brand); var categoria = trim(item.strategicDescription || item.strategic_description || item.categoria); if (!categoria) { if (categoryMap == null) { var categorization = loadStrategicCategoryMap(constraints, 30000); categoryMap = categorization.map || {}; categoryDiag = categorization.diag || ""; } var strategicId = resolveStrategicId(item, code); categoria = resolveCategory(categoryMap, strategicId); } var blob = normalize([code, desc, brand, trim(item.id), categoria].join(" ")); if (searchNorm && searchNorm.length >= 2 && blob.indexOf(searchNorm) === -1) { continue; } dataset.addRow([ code, desc, codigoDescricao, desc, code, brand, trim(item.ncmId), categoria ]); if (dataset.rowsCount >= maxRows) { break; } } if (dataset.rowsCount === 0) { var suffix = categoryDiag ? " | Categoria: " + categoryDiag : ""; addDiagRow(dataset, "Sem produtos apos filtros (busca: " + filtro.search + ")" + suffix); } } catch (e) { addDiagRow(dataset, "Erro ao consultar API: " + e); } return dataset; } function onMobileSync(user) {} function parseConstraints(constraints) { var out = { search: "", maxRows: 200 }; if (!constraints) { return out; } for (var i = 0; i < constraints.length; i++) { var c = constraints[i]; if (!c || !c.fieldName) continue; var name = String(c.fieldName); var lowerName = name.toLowerCase(); var value = cleanSearchValue(c.initialValue); if (lowerName === "sqllimit") { var n = parseInt(value, 10); if (!isNaN(n) && n > 0 && n <= 1000) { out.maxRows = n; } continue; } if ( value && lowerName !== "metadata#id" && lowerName !== "metadata#active" && lowerName !== "sqllimit" && lowerName !== "gbclientid" && lowerName !== "gbclientsecret" && lowerName !== "clientid" && lowerName !== "clientsecret" ) { if (!out.search || value.length > out.search.length) { out.search = value; } } } return out; } function cleanSearchValue(v) { var s = trim(v); s = s.replace(/[%*_]/g, ""); // Evita que flags comuns do Fluig virem termo de busca if (s === "true" || s === "false" || s === "on" || s === "off" || s === "1") { return ""; } return trim(s); } function normalize(v) { return trim(v).toLowerCase(); } function trim(v) { return String(v == null ? "" : v).trim(); } function parseJsonSafe(text) { try { return JSON.parse(text); } catch (e) { return null; } } function extractItems(obj) { if (!obj) return []; if (obj instanceof Array) return obj; if (obj.data && obj.data instanceof Array) return obj.data; if (obj.content) { if (obj.content instanceof Array) return obj.content; if (typeof obj.content === "string") { var parsedContent = parseJsonSafe(obj.content); if (parsedContent && parsedContent.data && parsedContent.data instanceof Array) { return parsedContent.data; } if (parsedContent && parsedContent instanceof Array) { return parsedContent; } } if (obj.content.data && obj.content.data instanceof Array) return obj.content.data; } if (obj.result) { if (obj.result instanceof Array) return obj.result; if (typeof obj.result === "string") { var parsedResult = parseJsonSafe(obj.result); if (parsedResult && parsedResult.data && parsedResult.data instanceof Array) { return parsedResult.data; } } } return []; } function getConstraintValue(constraints, fieldName) { if (!constraints || !fieldName) return ""; var target = String(fieldName).toLowerCase(); for (var i = 0; i < constraints.length; i++) { var c = constraints[i]; if (!c || !c.fieldName) continue; if (String(c.fieldName).toLowerCase() === target) { return c.initialValue; } } return ""; } function resolveGbCredentials(constraints) { var clientId = trim(getConstraintValue(constraints, "gbClientId")); if (!clientId) clientId = trim(getConstraintValue(constraints, "clientId")); if (!clientId) { try { clientId = trim(java.lang.System.getenv("GB_CLIENT_ID")); } catch (e1) {} } if (!clientId) clientId = DEFAULT_GB_CLIENT_ID; var clientSecret = trim(getConstraintValue(constraints, "gbClientSecret")); if (!clientSecret) clientSecret = trim(getConstraintValue(constraints, "clientSecret")); if (!clientSecret) { try { clientSecret = trim(java.lang.System.getenv("GB_CLIENT_SECRET")); } catch (e2) {} } if (!clientSecret) clientSecret = DEFAULT_GB_CLIENT_SECRET; return { clientId: clientId, clientSecret: clientSecret }; } function loadStrategicCategoryMap(constraints, timeoutMs) { var out = { map: {}, diag: "" }; var creds = resolveGbCredentials(constraints); if (!creds.clientId || !creds.clientSecret) { out.diag = "credenciais ausentes"; return out; } var tokenResp = requestGbToken(creds, timeoutMs || 30000); if (!tokenResp.token) { out.diag = tokenResp.diag || "falha ao obter token"; return out; } var strategicsResp = requestStrategics(tokenResp.token, timeoutMs || 30000); var strategics = strategicsResp.items || []; if (!strategics.length) { out.diag = strategicsResp.diag || "sem classificacoes"; return out; } for (var i = 0; i < strategics.length; i++) { var item = strategics[i] || {}; var id = trim(item.strategicId || item.strategicID || item.id || item.code); var descricao = trim(item.description || item.descricao || item.category || item.name); if (!id || !descricao) continue; out.map[id] = descricao; } if (!hasOwnKeys(out.map)) { out.diag = "classificacoes sem strategicId/description"; } return out; } function requestGbToken(creds, timeoutMs) { var timeout = timeoutMs || 30000; var body = "client_id=" + urlEncode(creds.clientId) + "&client_secret=" + urlEncode(creds.clientSecret); var attempts = [ { name: "post-query-body", method: "POST", url: GB_TOKEN_URL + "?grant_type=client_credentials", headers: { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded" }, body: body } ]; var trace = []; for (var i = 0; i < attempts.length; i++) { var attempt = attempts[i]; var resp = httpRequest(attempt.url, attempt.method, attempt.headers, attempt.body, timeout); trace.push(attempt.name + ":" + trim(resp.status)); var parsed = normalizeApiBody(resp.body); var token = trim(parsed && (parsed.access_token || parsed.accessToken || parsed.token)); if (token) { return { token: token, diag: "token ok (" + attempt.name + ")" }; } } return { token: "", diag: "token falhou [" + trace.join(" | ") + "]" }; } function requestStrategics(accessToken, timeoutMs) { var resp = httpRequest( GB_STRATEGICS_URL, "GET", { "Accept": "application/json", "Authorization": "Bearer " + trim(accessToken) }, "", timeoutMs || 30000 ); var parsed = normalizeApiBody(resp.body); var items = extractItems(parsed); if ((!items || !items.length) && parsed && parsed.items instanceof Array) { items = parsed.items; } if ((!items || !items.length) && parsed && parsed.strategics instanceof Array) { items = parsed.strategics; } if (!items || !items.length) { return { items: [], diag: "strategics HTTP " + trim(resp.status) }; } return { items: items, diag: "ok" }; } function resolveStrategicId(item, fallbackCode) { var candidates = [ item && item.strategicId, item && item.strategicID, item && item.classificationStrategicId, item && item.productStrategicId, item && item.estrategicId, item && item.strategyId, item && item.code, fallbackCode ]; for (var i = 0; i < candidates.length; i++) { var value = trim(candidates[i]); if (value) return value; } return ""; } function resolveCategory(map, strategicId) { var id = trim(strategicId); if (!id || !map) return ""; if (map.hasOwnProperty(id)) { return trim(map[id]); } var asInt = parseInt(id, 10); if (!isNaN(asInt)) { var normalized = String(asInt); if (map.hasOwnProperty(normalized)) { return trim(map[normalized]); } } return ""; } function normalizeApiBody(text) { var obj = parseJsonSafe(text); if (!obj) return null; if (obj.content && typeof obj.content === "string") { var parsedContent = parseJsonSafe(obj.content); if (parsedContent) return parsedContent; } if (obj.result && typeof obj.result === "string") { var parsedResult = parseJsonSafe(obj.result); if (parsedResult) return parsedResult; } return obj; } function hasOwnKeys(obj) { for (var k in obj) { if (obj.hasOwnProperty(k)) return true; } return false; } function urlEncode(value) { return String(java.net.URLEncoder.encode(String(value || ""), "UTF-8")); } function addDiagRow(dataset, msg) { dataset.addRow([ "DEBUG", String(msg), String(msg), String(msg), "", "", "", "" ]); } function fetchDirect(url, timeoutMs) { return httpRequest( url, "GET", { "Accept": "application/json" }, "", timeoutMs || 30000 ); } function httpRequest(url, method, headers, body, timeoutMs) { var conn = null; var reader = null; var writer = null; try { var URL = java.net.URL; var InputStreamReader = java.io.InputStreamReader; var BufferedReader = java.io.BufferedReader; var OutputStreamWriter = java.io.OutputStreamWriter; var StringBuilder = java.lang.StringBuilder; var httpMethod = String(method || "GET").toUpperCase(); var timeout = timeoutMs || 30000; var payload = body == null ? "" : String(body); conn = new URL(url).openConnection(); conn.setRequestMethod(httpMethod); conn.setConnectTimeout(timeout); conn.setReadTimeout(timeout); if (headers) { for (var h in headers) { if (!headers.hasOwnProperty(h)) continue; if (headers[h] == null || headers[h] === "") continue; conn.setRequestProperty(String(h), String(headers[h])); } } if (payload && (httpMethod === "POST" || httpMethod === "PUT" || httpMethod === "PATCH")) { conn.setDoOutput(true); writer = new OutputStreamWriter(conn.getOutputStream(), "UTF-8"); writer.write(payload); writer.flush(); } var statusCode = conn.getResponseCode(); var status = String(statusCode); var stream = (statusCode >= 200 && statusCode < 300) ? conn.getInputStream() : conn.getErrorStream(); if (stream == null) { return { status: status, body: "" }; } reader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); var sb = new StringBuilder(); var line = null; while ((line = reader.readLine()) != null) { sb.append(line); } return { status: status, body: String(sb.toString()) }; } catch (e) { return { status: "", body: "" }; } finally { try { if (writer) writer.close(); } catch (e1) {} try { if (reader) reader.close(); } catch (e2) {} try { if (conn) conn.disconnect(); } catch (e3) {} } }