diff --git a/Transferência Ginseng/.vscode/settings.json b/Transferência Ginseng/.vscode/settings.json index 6def96a..aa86c45 100644 --- a/Transferência Ginseng/.vscode/settings.json +++ b/Transferência Ginseng/.vscode/settings.json @@ -1,3 +1,4 @@ { - "totvsLanguageServer.welcomePage": false + "totvsLanguageServer.welcomePage": false, + "totvsLanguageServer.editor.linter.includes": "C:\\25-04-14-P12-SMARTCLIENT_BUILD 20.3.2.12_WINDOWS_X64\\include" } \ No newline at end of file diff --git a/Transferência Ginseng/datasets/ds_LojasTransf.js b/Transferência Ginseng/datasets/ds_LojasTransf.js index d6c4ad9..1273d55 100644 --- a/Transferência Ginseng/datasets/ds_LojasTransf.js +++ b/Transferência Ginseng/datasets/ds_LojasTransf.js @@ -18,7 +18,7 @@ function createDataset(fields, constraints, sortFields) { var clientService = fluigAPI.getAuthorizeClientService(); var data = { companyId: String(getValue("WKCompany") || "1"), - serviceCode: "GINSENG APITESTE", // ajuste para o codigo do servico cadastrado no Fluig + serviceCode: "GINSENG API", // ajuste para o codigo do servico cadastrado no Fluig endpoint: "/base_pdvs", method: "get", timeoutService: "60000", diff --git a/Transferência Ginseng/datasets/ds_fiscal_invoice_by_keys.js b/Transferência Ginseng/datasets/ds_fiscal_invoice_by_keys.js index ad4ffc2..259ac84 100644 --- a/Transferência Ginseng/datasets/ds_fiscal_invoice_by_keys.js +++ b/Transferência Ginseng/datasets/ds_fiscal_invoice_by_keys.js @@ -236,7 +236,7 @@ function invokeAuthorizedGet(clientService, endpoint, auth) { var data = { companyId: String(getValue("WKCompany") || "1"), - serviceCode: "GINSENG APITESTE", + serviceCode: "GinsengAPI2", endpoint: endpoint, method: "get", timeoutService: "30000", diff --git a/Transferência Ginseng/datasets/ds_rgb_products.js b/Transferência Ginseng/datasets/ds_rgb_products.js index 0fc0eb6..a9daf36 100644 --- a/Transferência Ginseng/datasets/ds_rgb_products.js +++ b/Transferência Ginseng/datasets/ds_rgb_products.js @@ -6,10 +6,16 @@ function defineStructure() { 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"); @@ -19,6 +25,7 @@ function createDataset(fields, constraints, sortFields) { dataset.addColumn("sku"); dataset.addColumn("brand"); dataset.addColumn("ncmId"); + dataset.addColumn("categoria"); try { var filtro = parseConstraints(constraints); @@ -62,6 +69,8 @@ function createDataset(fields, constraints, sortFields) { 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] || {}; @@ -77,7 +86,17 @@ function createDataset(fields, constraints, sortFields) { var desc = trim(item.description); var codigoDescricao = code + " - " + desc; var brand = trim(item.brand); - var blob = normalize([code, desc, brand, trim(item.id)].join(" ")); + 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; @@ -90,7 +109,8 @@ function createDataset(fields, constraints, sortFields) { desc, code, brand, - trim(item.ncmId) + trim(item.ncmId), + categoria ]); if (dataset.rowsCount >= maxRows) { @@ -99,7 +119,8 @@ function createDataset(fields, constraints, sortFields) { } if (dataset.rowsCount === 0) { - addDiagRow(dataset, "Sem produtos apos filtros (busca: " + filtro.search + ")"); + var suffix = categoryDiag ? " | Categoria: " + categoryDiag : ""; + addDiagRow(dataset, "Sem produtos apos filtros (busca: " + filtro.search + ")" + suffix); } } catch (e) { @@ -126,9 +147,10 @@ function parseConstraints(constraints) { if (!c || !c.fieldName) continue; var name = String(c.fieldName); + var lowerName = name.toLowerCase(); var value = cleanSearchValue(c.initialValue); - if (name === "sqlLimit") { + if (lowerName === "sqllimit") { var n = parseInt(value, 10); if (!isNaN(n) && n > 0 && n <= 1000) { out.maxRows = n; @@ -138,9 +160,13 @@ function parseConstraints(constraints) { if ( value && - name !== "metadata#id" && - name !== "metadata#active" && - name !== "sqlLimit" + 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; @@ -209,6 +235,205 @@ function extractItems(obj) { 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", @@ -223,23 +448,53 @@ function addDiagRow(dataset, 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 HttpURLConnection = java.net.HttpURLConnection; var InputStreamReader = java.io.InputStreamReader; var BufferedReader = java.io.BufferedReader; + var OutputStreamWriter = java.io.OutputStreamWriter; var StringBuilder = java.lang.StringBuilder; - conn = new URL(url).openConnection(); - conn.setRequestMethod("GET"); - conn.setConnectTimeout(timeoutMs || 30000); - conn.setReadTimeout(timeoutMs || 30000); - conn.setRequestProperty("Accept", "application/json"); + var httpMethod = String(method || "GET").toUpperCase(); + var timeout = timeoutMs || 30000; + var payload = body == null ? "" : String(body); - var status = conn.getResponseCode(); - var stream = (status >= 200 && status < 300) ? conn.getInputStream() : conn.getErrorStream(); + 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: "" }; } @@ -251,14 +506,12 @@ function fetchDirect(url, timeoutMs) { sb.append(line); } - return { - status: status, - body: String(sb.toString()) - }; + return { status: status, body: String(sb.toString()) }; } catch (e) { - return { status: 0, body: "" }; + return { status: "", body: "" }; } finally { - try { if (reader) reader.close(); } catch (e1) {} - try { if (conn) conn.disconnect(); } catch (e2) {} + try { if (writer) writer.close(); } catch (e1) {} + try { if (reader) reader.close(); } catch (e2) {} + try { if (conn) conn.disconnect(); } catch (e3) {} } } diff --git a/Transferência Ginseng/datasets/ds_rgb_products_v2.js b/Transferência Ginseng/datasets/ds_rgb_products_v2.js new file mode 100644 index 0000000..cf0783c --- /dev/null +++ b/Transferência Ginseng/datasets/ds_rgb_products_v2.js @@ -0,0 +1,517 @@ +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 (maxRows > 0 && 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: 0 + }; + + 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(trim(c.initialValue), 10); + if (!isNaN(n) && n > 0) { + 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) {} + } +} diff --git a/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/.metadata b/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/.metadata index d744d9a..0a702dd 100644 Binary files a/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/.metadata and b/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/.metadata differ diff --git a/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/excel.js b/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/excel.js index e1d8155..893d865 100644 --- a/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/excel.js +++ b/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/excel.js @@ -97,6 +97,7 @@ function processarArquivoExcel(file) { var codigo = getCellByAliases(item, ["codigoItem", "codigo", "codItem", "sku", "code", "item"]); var quantidade = getCellByAliases(item, ["quantidadeItem", "quantidade", "qtd", "qtde"]); var descricao = getCellByAliases(item, ["descricao", "description", "desc"]); + var categoria = getCellByAliases(item, ["categoria", "category"]); if (!codigo || !quantidade) { return; @@ -105,7 +106,8 @@ function processarArquivoExcel(file) { linhasValidas.push({ codigo: String(codigo).trim(), quantidade: String(quantidade).trim(), - descricao: String(descricao || "").trim() + descricao: String(descricao || "").trim(), + categoria: String(categoria || "").trim() }); }); @@ -141,6 +143,11 @@ function processarArquivoExcel(file) { if (descricaoFinal) { $("#codigoItem___" + idx).val(descricaoFinal); } + + var categoriaFinal = item.categoria || produtoInfo.categoria; + if (categoriaFinal) { + $("#categoriaItem___" + idx).val(categoriaFinal); + } }); if (typeof processarConferenciaNfe === "function") { @@ -192,16 +199,16 @@ function normalizeHeader(text) { function buscarProdutoPorCodigo(codigo) { try { if (typeof DatasetFactory === "undefined" || typeof ConstraintType === "undefined") { - return { descricao: "", id: "" }; + return { descricao: "", id: "", categoria: "" }; } var codigoTxt = String(codigo || "").trim(); - if (!codigoTxt) return { descricao: "", id: "" }; + if (!codigoTxt) return { descricao: "", id: "", categoria: "" }; var cCodigo = DatasetFactory.createConstraint("Code", codigoTxt, codigoTxt, ConstraintType.MUST); - var ds = DatasetFactory.getDataset("ds_rgb_products", null, [cCodigo], null); + var ds = DatasetFactory.getDataset("ds_rgb_products_v2", null, [cCodigo], null); if (!ds || !ds.values || !ds.values.length) { - return { descricao: "", id: "" }; + return { descricao: "", id: "", categoria: "" }; } for (var i = 0; i < ds.values.length; i++) { @@ -209,7 +216,8 @@ function buscarProdutoPorCodigo(codigo) { if (String(row.Code || "").trim() === codigoTxt) { return { descricao: String(row.descricao || row.Description || "").trim(), - id: String(row.id || "").trim() + id: String(row.id || "").trim(), + categoria: String(row.categoria || row.strategicDescription || "").trim() }; } } @@ -217,11 +225,12 @@ function buscarProdutoPorCodigo(codigo) { var first = ds.values[0] || {}; return { descricao: String(first.descricao || first.Description || "").trim(), - id: String(first.id || "").trim() + id: String(first.id || "").trim(), + categoria: String(first.categoria || first.strategicDescription || "").trim() }; } catch (e) { console.error("Erro ao buscar descricao por codigo:", e); - return { descricao: "", id: "" }; + return { descricao: "", id: "", categoria: "" }; } } diff --git a/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/script.js b/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/script.js index 59e9ee1..535fd70 100644 --- a/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/script.js +++ b/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/script.js @@ -49,13 +49,15 @@ $(document).ready(function () { processarConferenciaNfe(); }); + var activity = String($("#activity").val() || ""); + applyTransferStatus(activity); + if ($("#formMode").val() == "VIEW") { showAndBlock(["all"]); $("#btnConsultarChaveNfe").prop("disabled", true).hide(); - updateConferenciaNfeVisibility($("#activity").val()); + updateConferenciaNfeVisibility(activity); } else { //show the right fields - var activity = $("#activity").val(); var requestDate = getCurrentDate(); if (String(activity) !== "6") { @@ -209,6 +211,40 @@ $(document).ready(function () { }); +function applyTransferStatus(activity) { + var current = String(activity || ""); + var pills = $("#transferStatus .status-pill"); + if (!pills.length) return; + + pills.removeClass("is-active is-done"); + + var activeOrder = -1; + pills.each(function () { + var pill = $(this); + var activities = String(pill.attr("data-activities") || "").split(","); + for (var i = 0; i < activities.length; i++) { + if ($.trim(activities[i]) === current) { + pill.addClass("is-active"); + var order = parseInt(pill.attr("data-order"), 10); + if (!isNaN(order)) { + activeOrder = order; + } + break; + } + } + }); + + if (activeOrder < 0) return; + + pills.each(function () { + var pill = $(this); + var order = parseInt(pill.attr("data-order"), 10); + if (!isNaN(order) && order < activeOrder) { + pill.addClass("is-done"); + } + }); +} + function resolveFormModeFallback() { var mode = ($("#formMode").val() || "").toUpperCase(); if (mode) return mode; @@ -1312,9 +1348,11 @@ function setSelectedZoomItem(selectedItem) { var itemDescricao = selectedItem["descricao"] || selectedItem["Description"] || ""; var itemCode = selectedItem["Code"] || selectedItem["sku"] || ""; var itemProductId = selectedItem["id"] || selectedItem["productId"] || ""; + var itemCategoria = selectedItem["categoria"] || selectedItem["strategicDescription"] || ""; $("#codigoItem" + "___" + indice).val(itemDescricao); $("#codigoProdutoItem" + "___" + indice).val(itemCode); $("#productIdItem" + "___" + indice).val(itemProductId); + $("#categoriaItem" + "___" + indice).val(itemCategoria); processarConferenciaNfe(); } @@ -1355,6 +1393,7 @@ function removedZoomItem(removedItem) { $("#codigoItem___" + linha[1]).val(""); $("#codigoProdutoItem___" + linha[1]).val(""); $("#productIdItem___" + linha[1]).val(""); + $("#categoriaItem___" + linha[1]).val(""); $("#quantidadeItem___" + linha[1]).val(""); processarConferenciaNfe(); } @@ -1364,6 +1403,7 @@ function removedZoomItem(removedItem) { $("#codigoItem" + "___" + indice).val(""); $("#codigoProdutoItem" + "___" + indice).val(""); $("#productIdItem" + "___" + indice).val(""); + $("#categoriaItem" + "___" + indice).val(""); processarConferenciaNfe(); } } diff --git a/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/totvsflow_solicitacao_transferencia.html b/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/totvsflow_solicitacao_transferencia.html index 767928e..d9a87af 100644 --- a/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/totvsflow_solicitacao_transferencia.html +++ b/Transferência Ginseng/forms/totvsflow_solicitacao_transferencia/totvsflow_solicitacao_transferencia.html @@ -25,13 +25,40 @@ } .status-pill { - background: #e9f4ff; - color: #0d5b91; - border: 1px solid #c3def6; + background: #eef2f6; + color: #5f7080; + border: 1px solid #d3dde7; padding: 6px 12px; border-radius: 999px; font-size: 11px; font-weight: 600; + transition: all .2s ease; + } + + .status-pill.is-done { + background: #e8f7ed; + color: #1f6e3e; + border-color: #b8e3c4; + } + + .status-pill.is-active { + background: #e8f2ff; + color: #0e56a2; + border-color: #8fb8e8; + box-shadow: 0 0 0 2px rgba(31, 110, 169, 0.12); + } + + .status-pill.status-pill--problem.is-active { + background: #ffecec; + color: #a12f2f; + border-color: #efb1b1; + box-shadow: 0 0 0 2px rgba(199, 58, 58, 0.12); + } + + .status-pill.status-pill--problem.is-done { + background: #fff4e6; + color: #8a5c12; + border-color: #f2d3a2; } .transfer-main-title { @@ -216,11 +243,15 @@