att
This commit is contained in:
parent
7113b026ef
commit
e712c300c6
11
Lançamento de documentos/.project
Normal file
11
Lançamento de documentos/.project
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>Lançamento de documentos</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
Binary file not shown.
@ -1,42 +0,0 @@
|
|||||||
function createDataset(fields, constraints, sortFields) {
|
|
||||||
var dataset = DatasetBuilder.newDataset();
|
|
||||||
dataset.addColumn("STATUS");
|
|
||||||
dataset.addColumn("CAMPO");
|
|
||||||
dataset.addColumn("VALOR");
|
|
||||||
|
|
||||||
try {
|
|
||||||
dataset.addRow(["DEBUG", "__version__", "dsPortalFornecedorNF_debug_2026_03_12"]);
|
|
||||||
|
|
||||||
if (!constraints || constraints.length === 0) {
|
|
||||||
dataset.addRow(["DEBUG", "__constraints__", "vazio"]);
|
|
||||||
return dataset;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < constraints.length; i++) {
|
|
||||||
var c = constraints[i];
|
|
||||||
var fieldName = getFieldNameSafe(c);
|
|
||||||
var initialValue = getInitialValueSafe(c);
|
|
||||||
dataset.addRow(["DEBUG", fieldName, initialValue]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataset;
|
|
||||||
} catch (e) {
|
|
||||||
var erro = (e && e.message) ? e.message : ("" + e);
|
|
||||||
dataset.addRow(["ERRO", "__exception__", erro]);
|
|
||||||
return dataset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFieldNameSafe(c) {
|
|
||||||
if (!c) return "";
|
|
||||||
if (typeof c.getFieldName === "function") return (c.getFieldName() || "") + "";
|
|
||||||
if (c.fieldName !== undefined && c.fieldName !== null) return (c.fieldName || "") + "";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getInitialValueSafe(c) {
|
|
||||||
if (!c) return "";
|
|
||||||
if (typeof c.getInitialValue === "function") return (c.getInitialValue() || "") + "";
|
|
||||||
if (c.initialValue !== undefined && c.initialValue !== null) return (c.initialValue || "") + "";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
@ -0,0 +1,174 @@
|
|||||||
|
function createDataset(fields, constraints, sortFields) {
|
||||||
|
var dataset = DatasetBuilder.newDataset();
|
||||||
|
dataset.addColumn("STATUS");
|
||||||
|
dataset.addColumn("MESSAGE");
|
||||||
|
dataset.addColumn("PROCESS_INSTANCE_ID");
|
||||||
|
dataset.addColumn("RAW_RESPONSE");
|
||||||
|
|
||||||
|
try {
|
||||||
|
var params = constraintsToMap(constraints);
|
||||||
|
validateRequired(params);
|
||||||
|
|
||||||
|
var payload = {
|
||||||
|
targetState: parseInt(params.targetState || "5", 10),
|
||||||
|
comment: params.comment || "Envio via portal fornecedor",
|
||||||
|
formFields: {
|
||||||
|
data_abertura: valueOrEmpty(params.data_abertura),
|
||||||
|
emitido_por: valueOrEmpty(params.emitido_por),
|
||||||
|
entidade_responsavel: valueOrEmpty(params.entidade_responsavel),
|
||||||
|
tipo_cadastro: valueOrEmpty(params.tipo_cadastro),
|
||||||
|
emailSolicitante: valueOrEmpty(params.emailSolicitante),
|
||||||
|
cpf: valueOrEmpty(params.cpf),
|
||||||
|
tipo_documento: valueOrEmpty(params.tipo_documento),
|
||||||
|
numero_documento: valueOrEmpty(params.numero_documento),
|
||||||
|
valor: valueOrEmpty(params.valor),
|
||||||
|
justificativa: valueOrEmpty(params.justificativa)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var clientService = fluigAPI.getAuthorizeClientService();
|
||||||
|
var requestData = {
|
||||||
|
companyId: getCompanyId(),
|
||||||
|
serviceCode: "fluig_rest",
|
||||||
|
endpoint: "/process-management/api/v2/processes/FlowEssentials_LancamentodeDocumento/start",
|
||||||
|
method: "post",
|
||||||
|
timeoutService: "100",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json"
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
encoding: "UTF-8",
|
||||||
|
mediaType: "application/json",
|
||||||
|
useSSL: true
|
||||||
|
},
|
||||||
|
params: payload
|
||||||
|
};
|
||||||
|
|
||||||
|
var vo = clientService.invoke(JSON.stringify(requestData));
|
||||||
|
var raw = vo ? String(vo.getResult() || "") : "";
|
||||||
|
if (!raw) {
|
||||||
|
throw "fluig_rest retornou vazio.";
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = parseJsonSafe(raw);
|
||||||
|
var processInstanceId = extractProcessInstanceId(response);
|
||||||
|
var responseMessage = extractResponseMessage(response);
|
||||||
|
|
||||||
|
if (isErrorResponse(response, raw)) {
|
||||||
|
dataset.addRow(["ERROR", responseMessage || "Falha ao iniciar processo.", processInstanceId, raw]);
|
||||||
|
return dataset;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataset.addRow(["OK", responseMessage || "Solicitação enviada com sucesso.", processInstanceId, raw]);
|
||||||
|
return dataset;
|
||||||
|
} catch (e) {
|
||||||
|
dataset.addRow(["ERROR", errorMessage(e), "", ""]);
|
||||||
|
return dataset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function constraintsToMap(constraints) {
|
||||||
|
var map = {};
|
||||||
|
if (!constraints) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < constraints.length; i++) {
|
||||||
|
var c = constraints[i];
|
||||||
|
var fieldName = getFieldNameSafe(c);
|
||||||
|
if (!fieldName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
map[fieldName] = getInitialValueSafe(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateRequired(params) {
|
||||||
|
var requiredFields = [
|
||||||
|
"data_abertura",
|
||||||
|
"emitido_por",
|
||||||
|
"entidade_responsavel",
|
||||||
|
"tipo_cadastro",
|
||||||
|
"cpf",
|
||||||
|
"numero_documento",
|
||||||
|
"justificativa"
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < requiredFields.length; i++) {
|
||||||
|
var fieldName = requiredFields[i];
|
||||||
|
if (!valueOrEmpty(params[fieldName])) {
|
||||||
|
throw "Campo obrigatório não informado: " + fieldName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractProcessInstanceId(response) {
|
||||||
|
if (!response) return "";
|
||||||
|
if (response.processInstanceId) return String(response.processInstanceId);
|
||||||
|
if (response.content && response.content.processInstanceId) return String(response.content.processInstanceId);
|
||||||
|
if (response.content && response.content.processInstanceid) return String(response.content.processInstanceid);
|
||||||
|
if (response.content && response.content.requestNumber) return String(response.content.requestNumber);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractResponseMessage(response) {
|
||||||
|
if (!response) return "";
|
||||||
|
if (response.message) return String(response.message);
|
||||||
|
if (response.detailedMessage) return String(response.detailedMessage);
|
||||||
|
if (response.content && response.content.message) return String(response.content.message);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isErrorResponse(response, raw) {
|
||||||
|
if (!response) return false;
|
||||||
|
if (response.code && !extractProcessInstanceId(response)) return true;
|
||||||
|
if (response.message && String(response.message).toLowerCase().indexOf("erro") >= 0 && !extractProcessInstanceId(response)) return true;
|
||||||
|
if (raw && raw.indexOf("\"code\"") >= 0 && !extractProcessInstanceId(response)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseJsonSafe(value) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch (e) {
|
||||||
|
return { raw: value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCompanyId() {
|
||||||
|
try {
|
||||||
|
if (typeof getValue === "function") {
|
||||||
|
return String(getValue("WKCompany") || "1");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
function valueOrEmpty(value) {
|
||||||
|
return value == null ? "" : String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function errorMessage(e) {
|
||||||
|
if (e && e.message) return String(e.message);
|
||||||
|
return String(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFieldNameSafe(c) {
|
||||||
|
if (!c) return "";
|
||||||
|
if (typeof c.getFieldName === "function") return String(c.getFieldName() || "");
|
||||||
|
if (c.fieldName !== undefined && c.fieldName !== null) return String(c.fieldName || "");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInitialValueSafe(c) {
|
||||||
|
if (!c) return "";
|
||||||
|
if (typeof c.getInitialValue === "function") return String(c.getInitialValue() || "");
|
||||||
|
if (c.initialValue !== undefined && c.initialValue !== null) return String(c.initialValue || "");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
Binary file not shown.
@ -1,4 +1,4 @@
|
|||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" type="text/css" href="/style-guide/css/fluig-style-guide.min.css">
|
<link rel="stylesheet" type="text/css" href="/style-guide/css/fluig-style-guide.min.css">
|
||||||
@ -79,7 +79,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 id="rcorners"> Lançamento de documento </h1>
|
<h1 id="rcorners"> Lançamento de documento </h1>
|
||||||
|
|
||||||
<div class="container activity-all">
|
<div class="container activity-all">
|
||||||
|
|
||||||
@ -90,7 +90,7 @@
|
|||||||
<h2>
|
<h2>
|
||||||
<i class="flaticon flaticon-account-box" aria-hidden="true"></i> Dados do documento
|
<i class="flaticon flaticon-account-box" aria-hidden="true"></i> Dados do documento
|
||||||
</h2>
|
</h2>
|
||||||
<h6>Dados referentes ao documento que será lançado.</h6>
|
<h6>Dados referentes ao documento que será lançado.</h6>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -117,7 +117,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group col-md-3 col-xs-12 divResposavelPelaEmissao divEntidadeResponsavel alertaCampo">
|
<div class="form-group col-md-3 col-xs-12 divResposavelPelaEmissao divEntidadeResponsavel alertaCampo">
|
||||||
<label for="entidade_responsavel"> Nome do responsável pela emissão</label>
|
<label for="entidade_responsavel"> Nome do responsável pela emissão</label>
|
||||||
<span class="required text-danger"><strong> * </strong></span>
|
<span class="required text-danger"><strong> * </strong></span>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@ -133,11 +133,11 @@
|
|||||||
/>
|
/>
|
||||||
<p class="help-block" id="entidadeResponsavel"
|
<p class="help-block" id="entidadeResponsavel"
|
||||||
style="display: none; position: absolute; font-size: 12px;">
|
style="display: none; position: absolute; font-size: 12px;">
|
||||||
Preenchimento obrigatório
|
Preenchimento obrigatório
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-3 col-xs-12">
|
<div class="form-group col-md-3 col-xs-12">
|
||||||
<label> E-mail do usuário </label>
|
<label> E-mail do usuário </label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
name="emailSolicitante"
|
name="emailSolicitante"
|
||||||
@ -161,13 +161,13 @@
|
|||||||
<label for="tipo_cadastro"> Tipo de cadastro </label><span
|
<label for="tipo_cadastro"> Tipo de cadastro </label><span
|
||||||
class="required text-danger"><strong> * </strong></span>
|
class="required text-danger"><strong> * </strong></span>
|
||||||
<select name="tipo_cadastro" id="tipo_cadastro" class="form-control">
|
<select name="tipo_cadastro" id="tipo_cadastro" class="form-control">
|
||||||
<option value="">Selecionar opção</option>
|
<option value="">Selecionar opção</option>
|
||||||
<option value="cpf">CPF</option>
|
<option value="cpf">CPF</option>
|
||||||
<option value="cnpj">CNPJ</option>
|
<option value="cnpj">CNPJ</option>
|
||||||
</select>
|
</select>
|
||||||
<p class="help-block" id="tipoCadastro"
|
<p class="help-block" id="tipoCadastro"
|
||||||
style="display: none; position: absolute; font-size: 12px;">Preenchimento
|
style="display: none; position: absolute; font-size: 12px;">Preenchimento
|
||||||
obrigatório</p>
|
obrigatório</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-3 col-xs-12 divCnpj alertaCampoj">
|
<div class="form-group col-md-3 col-xs-12 divCnpj alertaCampoj">
|
||||||
<label for="cnpj"> CNPJ </label> <span class="required text-danger"><strong> *
|
<label for="cnpj"> CNPJ </label> <span class="required text-danger"><strong> *
|
||||||
@ -176,7 +176,7 @@
|
|||||||
mask="00.000.000/0000-00" class="form-control" readonly />
|
mask="00.000.000/0000-00" class="form-control" readonly />
|
||||||
<p class="help-block" id="errorCnpj"
|
<p class="help-block" id="errorCnpj"
|
||||||
style="display: none; position: absolute; font-size: 12px;">Preenchimento
|
style="display: none; position: absolute; font-size: 12px;">Preenchimento
|
||||||
obrigatório</p>
|
obrigatório</p>
|
||||||
<p class="help-block" style="color: #cc3d3d;" id="mensagemErroCnpj"></p>
|
<p class="help-block" style="color: #cc3d3d;" id="mensagemErroCnpj"></p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -199,7 +199,7 @@
|
|||||||
/>
|
/>
|
||||||
<p class="help-block" id="errorCpf"
|
<p class="help-block" id="errorCpf"
|
||||||
style="display: none; position: absolute; font-size: 12px;">
|
style="display: none; position: absolute; font-size: 12px;">
|
||||||
Preenchimento obrigatório
|
Preenchimento obrigatório
|
||||||
</p>
|
</p>
|
||||||
<p class="help-block" style="color: #cc3d3d" id="mensagemErroCpf"></p>
|
<p class="help-block" style="color: #cc3d3d" id="mensagemErroCpf"></p>
|
||||||
</div>
|
</div>
|
||||||
@ -208,7 +208,7 @@
|
|||||||
<select name="tipo_documento" id="tipo_documento" class="form-control">
|
<select name="tipo_documento" id="tipo_documento" class="form-control">
|
||||||
<option value="">Selecionar tipo de documento</option>
|
<option value="">Selecionar tipo de documento</option>
|
||||||
<option value="danfe">Nota Fiscal de Mercadoria</option>
|
<option value="danfe">Nota Fiscal de Mercadoria</option>
|
||||||
<option value="nota_fiscal_servico">Nota Fiscal de Serviço</option>
|
<option value="nota_fiscal_servico">Nota Fiscal de Serviços</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -219,13 +219,13 @@
|
|||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<div class="form-input">
|
<div class="form-input">
|
||||||
<div class="form-group col-md-6 col-xs-12 divNumeroDocumento alertaCampo">
|
<div class="form-group col-md-6 col-xs-12 divNumeroDocumento alertaCampo">
|
||||||
<label> Número do documento </label><span class="required text-danger"><strong> *
|
<label> Número do documento </label><span class="required text-danger"><strong> *
|
||||||
</strong></span>
|
</strong></span>
|
||||||
<input type="text" name="numero_documento" id="numero_documento"
|
<input type="text" name="numero_documento" id="numero_documento"
|
||||||
placeholder="Inserir número do documento" class="form-control" />
|
placeholder="Inserir número do documento" class="form-control" />
|
||||||
<p class="help-block" id="numeroDocumento"
|
<p class="help-block" id="numeroDocumento"
|
||||||
style="display: none; position: absolute; font-size: 12px;">Preenchimento
|
style="display: none; position: absolute; font-size: 12px;">Preenchimento
|
||||||
obrigatório</p>
|
obrigatório</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-6 col-xs-12">
|
<div class="form-group col-md-6 col-xs-12">
|
||||||
<label for="valor_contrato"> Valor do documento (se houver)</label>
|
<label for="valor_contrato"> Valor do documento (se houver)</label>
|
||||||
@ -245,8 +245,8 @@
|
|||||||
<label id="labelAnexaCota">Anexar documento</label>
|
<label id="labelAnexaCota">Anexar documento</label>
|
||||||
<span class="required text-danger"> <strong> * </strong>
|
<span class="required text-danger"> <strong> * </strong>
|
||||||
</span>
|
</span>
|
||||||
<p id="descAnexaCota">Utilize a aba anexos para anexar o documento ou o botão
|
<p id="descAnexaCota">Utilize a aba anexos para anexar o documento ou o botão
|
||||||
abaixo. <strong> Anexo obrigatório. </strong></p>
|
abaixo. <strong> Anexo obrigatório. </strong></p>
|
||||||
<input type="button" class="btn btn-primary" id="anexaDocumento"
|
<input type="button" class="btn btn-primary" id="anexaDocumento"
|
||||||
value="Anexar documento" onclick="showCamera('anexo_documento');"
|
value="Anexar documento" onclick="showCamera('anexo_documento');"
|
||||||
style="margin-top: 25px;" />
|
style="margin-top: 25px;" />
|
||||||
@ -258,21 +258,21 @@
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
<h2><i class="flaticon flaticon-message-question" aria-hidden="true">
|
<h2><i class="flaticon flaticon-message-question" aria-hidden="true">
|
||||||
</i> Descrição dos serviços
|
</i> Descrição dos serviços
|
||||||
|
|
||||||
</h2>
|
</h2>
|
||||||
<h6>Descrição detalhada dos serviços prestados e as possÃveis informações complementares.</h6>
|
<h6>Descrição detalhada dos serviços prestados e as possíveis informações complementares.</h6>
|
||||||
<br>
|
<br>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<div class="form-input">
|
<div class="form-input">
|
||||||
<div class="form-group col-md-12 col-xs-12 divJustificativa alertaCampo">
|
<div class="form-group col-md-12 col-xs-12 divJustificativa alertaCampo">
|
||||||
<label for="justificativa"> Descrição dos serviços </label> <span
|
<label for="justificativa"> Descrição dos serviços </label> <span
|
||||||
class="required text-danger"><strong> * </strong></span>
|
class="required text-danger"><strong> * </strong></span>
|
||||||
<textarea class="form-control" rows="3" id="justificativa" name="justificativa"
|
<textarea class="form-control" rows="3" id="justificativa" name="justificativa"
|
||||||
placeholder="Descreva os serviços prestados."></textarea>
|
placeholder="Descreva os serviços prestados."></textarea>
|
||||||
<p class="help-block" id="msgJustificativa" style="display: none;">Preenchimento
|
<p class="help-block" id="msgJustificativa" style="display: none;">Preenchimento
|
||||||
obrigatório</p>
|
obrigatório</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -288,9 +288,9 @@
|
|||||||
<div class="activity activity-5" style="display: none;">
|
<div class="activity activity-5" style="display: none;">
|
||||||
<div>
|
<div>
|
||||||
<br>
|
<br>
|
||||||
<h2><i class="flaticon flaticon-check-circle" aria-hidden="true"></i> Análise do documento
|
<h2><i class="flaticon flaticon-check-circle" aria-hidden="true"></i> Análise do documento
|
||||||
</h2>
|
</h2>
|
||||||
<h6>Informações complementares sobre a análise do documento pelo setor responsável.</h6>
|
<h6>Informações complementares sobre a análise do documento pelo setor responsável.</h6>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -298,14 +298,14 @@
|
|||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<div class="form-input">
|
<div class="form-input">
|
||||||
<div class="form-group col-md-10 col-xs-6">
|
<div class="form-group col-md-10 col-xs-6">
|
||||||
<label> Responsável por lançamento de documentos </label>
|
<label> Responsável por lançamento de documentos </label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="user_validacao_gestor"
|
name="user_validacao_gestor"
|
||||||
id="user_validacao_gestor"
|
id="user_validacao_gestor"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
readonly
|
readonly
|
||||||
data-protection="Responsável por lançamento de documentos"
|
data-protection="Responsável por lançamento de documentos"
|
||||||
data-protection-anonymizable
|
data-protection-anonymizable
|
||||||
data-protection-sensitive
|
data-protection-sensitive
|
||||||
data-protection-name
|
data-protection-name
|
||||||
@ -343,12 +343,12 @@
|
|||||||
<div class="form-input">
|
<div class="form-input">
|
||||||
<div class="form-group col-md-8 col-xs-12">
|
<div class="form-group col-md-8 col-xs-12">
|
||||||
<div>
|
<div>
|
||||||
<label for="radio_ged">Gestão eletrônica de documentos (ECM)</label>
|
<label for="radio_ged">Gestão eletrônica de documentos (ECM)</label>
|
||||||
</div>
|
</div>
|
||||||
<label class="radio-inline">
|
<label class="radio-inline">
|
||||||
<input type="radio" name="radio_ged" id="nao_publica_ged"
|
<input type="radio" name="radio_ged" id="nao_publica_ged"
|
||||||
value="nao_publica_ged" onchange="checkItemType()">
|
value="nao_publica_ged" onchange="checkItemType()">
|
||||||
Não publicar no ECM
|
Não publicar no ECM
|
||||||
</label>
|
</label>
|
||||||
<label class="radio-inline">
|
<label class="radio-inline">
|
||||||
<input type="radio" name="radio_ged" id="publica_ged" value="publica_ged"
|
<input type="radio" name="radio_ged" id="publica_ged" value="publica_ged"
|
||||||
@ -379,7 +379,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p class="help-block" id="pastaGed"
|
<p class="help-block" id="pastaGed"
|
||||||
style="display: none; position: absolute; font-size: 12px; font-size: 12px;">
|
style="display: none; position: absolute; font-size: 12px; font-size: 12px;">
|
||||||
Preenchimento obrigatório</p>
|
Preenchimento obrigatório</p>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -406,7 +406,7 @@
|
|||||||
Com data de validade
|
Com data de validade
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block" id="radioDataValidade" style="display: none;">Preenchimento
|
<p class="help-block" id="radioDataValidade" style="display: none;">Preenchimento
|
||||||
obrigatório</p>
|
obrigatório</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -416,17 +416,17 @@
|
|||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<div class="form-input divInicioExpiracaoValidade" style="display: none;">
|
<div class="form-input divInicioExpiracaoValidade" style="display: none;">
|
||||||
<div class="col-md-3 form-group">
|
<div class="col-md-3 form-group">
|
||||||
<label for="inicio_validade">InÃcio da validade</label>
|
<label for="inicio_validade">Início da validade</label>
|
||||||
<input type="date" class="form-control" id="inicio_validade" name="inicio_validade"
|
<input type="date" class="form-control" id="inicio_validade" name="inicio_validade"
|
||||||
placeholder="Selecionar data" />
|
placeholder="Selecionar data" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 form-group divExpiracaoValidade alertaCampo">
|
<div class="col-md-3 form-group divExpiracaoValidade alertaCampo">
|
||||||
<label for="expiracao_validade">Expiração da validade</label>
|
<label for="expiracao_validade">Expiração da validade</label>
|
||||||
<span class="required text-danger"><strong> * </strong></span>
|
<span class="required text-danger"><strong> * </strong></span>
|
||||||
<input type="date" class="form-control" id="expiracao_validade"
|
<input type="date" class="form-control" id="expiracao_validade"
|
||||||
name="expiracao_validade" placeholder="Selecionar data" />
|
name="expiracao_validade" placeholder="Selecionar data" />
|
||||||
<p class="help-block" id="expiracaoValidade" style="display: none;">Preenchimento
|
<p class="help-block" id="expiracaoValidade" style="display: none;">Preenchimento
|
||||||
obrigatório</p>
|
obrigatório</p>
|
||||||
</div><br>
|
</div><br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -436,12 +436,12 @@
|
|||||||
<div class="form-input divNotificarExpiracao alertaCampo" style="display: none;">
|
<div class="form-input divNotificarExpiracao alertaCampo" style="display: none;">
|
||||||
<br>
|
<br>
|
||||||
<div class="form-group col-md-12 col-xs-12">
|
<div class="form-group col-md-12 col-xs-12">
|
||||||
<label> Notificar expiração da validade do documento </label>
|
<label> Notificar expiração da validade do documento </label>
|
||||||
<p>Defina abaixo quantos dias antes da data de expiração do documento você deseja
|
<p>Defina abaixo quantos dias antes da data de expiração do documento você deseja
|
||||||
receber uma notificação. </p>
|
receber uma notificação. </p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-3 col-xs-12">
|
<div class="form-group col-md-3 col-xs-12">
|
||||||
<label> Dias antes da expiração </label>
|
<label> Dias antes da expiração </label>
|
||||||
<input type="number" class="form-control" name="dias_antes_expiracao"
|
<input type="number" class="form-control" name="dias_antes_expiracao"
|
||||||
id="dias_antes_expiracao" placeholder="0"
|
id="dias_antes_expiracao" placeholder="0"
|
||||||
oninput="validarNumeroPositivo(this); this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1');">
|
oninput="validarNumeroPositivo(this); this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1');">
|
||||||
@ -458,17 +458,7 @@
|
|||||||
<textarea class="form-control" name="justi_decisao_gestor"
|
<textarea class="form-control" name="justi_decisao_gestor"
|
||||||
id="justi_decisao_gestor"></textarea>
|
id="justi_decisao_gestor"></textarea>
|
||||||
<p class="help-block" id="justiDecisaoGestor" style="display: none;">Preenchimento
|
<p class="help-block" id="justiDecisaoGestor" style="display: none;">Preenchimento
|
||||||
obrigatório</p>
|
obrigatório</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="form-field">
|
|
||||||
<div class="form-input">
|
|
||||||
<div class="form-group col-md-12">
|
|
||||||
<label>Debug publicacao ECM</label>
|
|
||||||
<textarea class="form-control" rows="4" id="debug_publicacao_view" name="debug_publicacao_view" readonly></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -479,7 +469,7 @@
|
|||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<h6>Todos os campos com * são de preenchimento obrigatório.</h6>
|
<h6>Todos os campos com * são de preenchimento obrigatório.</h6>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -1131,8 +1121,8 @@
|
|||||||
|
|
||||||
function msgModal(size) {
|
function msgModal(size) {
|
||||||
FLUIGC.modal({
|
FLUIGC.modal({
|
||||||
title: "Atenção",
|
title: "Atenção",
|
||||||
content: "Existem campos que estão preenchidos incorretamente e/ou não foram preenchidos. Confira e realize as correções nos campos indicados.",
|
content: "Existem campos que estão preenchidos incorretamente e/ou não foram preenchidos. Confira e realize as correções nos campos indicados.",
|
||||||
id: 'fluig-modal',
|
id: 'fluig-modal',
|
||||||
size: size,
|
size: size,
|
||||||
actions: [{
|
actions: [{
|
||||||
@ -1156,7 +1146,7 @@
|
|||||||
document.getElementById("mensagemErroDiasExpiracao").textContent = "";
|
document.getElementById("mensagemErroDiasExpiracao").textContent = "";
|
||||||
} else {
|
} else {
|
||||||
// O valor não é um número positivo, exibe mensagem de erro
|
// O valor não é um número positivo, exibe mensagem de erro
|
||||||
document.getElementById("mensagemErroDiasExpiracao").textContent = "Digite um número positivo válido.";
|
document.getElementById("mensagemErroDiasExpiracao").textContent = "Digite um número positivo válido.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,117 @@
|
|||||||
|
# Portal Fornecedor - contrato do endpoint intermediario
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
A widget publica nao deve chamar diretamente:
|
||||||
|
|
||||||
|
- `/process-management/api/v2/processes/FlowEssentials_LancamentodeDocumento/start`
|
||||||
|
- `/api/public/ecm/dataset/datasets`
|
||||||
|
|
||||||
|
Ela deve chamar um endpoint intermediario no servidor, por exemplo:
|
||||||
|
|
||||||
|
- `POST /api/public/portalfornecedor/enviar`
|
||||||
|
|
||||||
|
Esse endpoint e quem usa `fluig_rest` no backend.
|
||||||
|
|
||||||
|
## Request esperado da widget
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"targetState": 5,
|
||||||
|
"comment": "Envio via portal fornecedor",
|
||||||
|
"formFields": {
|
||||||
|
"data_abertura": "2026-03-13",
|
||||||
|
"emitido_por": "fornecedor",
|
||||||
|
"entidade_responsavel": "Empresa X",
|
||||||
|
"tipo_cadastro": "cpf",
|
||||||
|
"emailSolicitante": "email@empresa.com.br",
|
||||||
|
"cpf": "12345678900",
|
||||||
|
"tipo_documento": "danfe",
|
||||||
|
"numero_documento": "123456",
|
||||||
|
"valor": "10,00",
|
||||||
|
"justificativa": "Descricao do servico"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response de sucesso
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Solicitacao enviada com sucesso.",
|
||||||
|
"processInstanceId": "12345",
|
||||||
|
"content": {
|
||||||
|
"processInstanceId": "12345"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response de erro
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"message": "Descricao do erro"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logica esperada no backend
|
||||||
|
|
||||||
|
1. Receber o JSON da widget.
|
||||||
|
2. Validar os campos obrigatorios.
|
||||||
|
3. Usar `fluigAPI.getAuthorizeClientService()`.
|
||||||
|
4. Invocar o servico `fluig_rest`.
|
||||||
|
5. Chamar o endpoint final:
|
||||||
|
`/process-management/api/v2/processes/FlowEssentials_LancamentodeDocumento/start`
|
||||||
|
6. Retornar para a widget somente o resultado final.
|
||||||
|
|
||||||
|
## Exemplo de chamada server-side
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var clientService = fluigAPI.getAuthorizeClientService();
|
||||||
|
|
||||||
|
var requestData = {
|
||||||
|
companyId: String(getValue("WKCompany") || "1"),
|
||||||
|
serviceCode: "fluig_rest",
|
||||||
|
endpoint: "/process-management/api/v2/processes/FlowEssentials_LancamentodeDocumento/start",
|
||||||
|
method: "post",
|
||||||
|
timeoutService: "100",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json"
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
encoding: "UTF-8",
|
||||||
|
mediaType: "application/json",
|
||||||
|
useSSL: true
|
||||||
|
},
|
||||||
|
params: payloadRecebidoDaWidget
|
||||||
|
};
|
||||||
|
|
||||||
|
var vo = clientService.invoke(JSON.stringify(requestData));
|
||||||
|
var raw = String(vo.getResult() || "");
|
||||||
|
var response = JSON.parse(raw);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuracao da widget
|
||||||
|
|
||||||
|
Por padrao a widget usa:
|
||||||
|
|
||||||
|
- `https://api.grupoginseng.com.br/v2/portalfornecedor/enviar_api_public_portalfornecedor_enviar_post`
|
||||||
|
|
||||||
|
Se necessario, sobrescreva antes de carregar a widget:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
window.portalfornecedorConfig = {
|
||||||
|
publicEndpointUrl: "https://api.grupoginseng.com.br/v2/portalfornecedor/enviar_api_public_portalfornecedor_enviar_post"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Observacao importante
|
||||||
|
|
||||||
|
`apiKey` no front nao substitui OAuth 1.0 do Fluig. Se existir um header como `apiKey`,
|
||||||
|
ele deve ser validado apenas no endpoint intermediario. O endpoint intermediario continua
|
||||||
|
sendo o responsavel por usar `fluig_rest` no servidor.
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
PORTAL_FORNECEDOR_BASE_URL=https://comerciode188006.fluig.cloudtotvs.com.br
|
||||||
|
PORTAL_FORNECEDOR_PROCESS_ID=FlowEssentials_LancamentodeDocumento
|
||||||
|
PORTAL_FORNECEDOR_CLIENT_KEY=your_consumer_key
|
||||||
|
PORTAL_FORNECEDOR_CLIENT_SECRET=your_consumer_secret
|
||||||
|
PORTAL_FORNECEDOR_RESOURCE_OWNER_KEY=your_access_token
|
||||||
|
PORTAL_FORNECEDOR_RESOURCE_OWNER_SECRET=your_token_secret
|
||||||
|
PORTAL_FORNECEDOR_COMPANY_ID=1
|
||||||
|
PORTAL_FORNECEDOR_PARENT_FOLDER_ID=10
|
||||||
|
PORTAL_FORNECEDOR_CORS_ORIGINS=https://comerciode188006.fluig.cloudtotvs.com.br
|
||||||
@ -0,0 +1,214 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from fastapi import FastAPI, File, Form, HTTPException, UploadFile
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from requests_oauthlib import OAuth1
|
||||||
|
|
||||||
|
|
||||||
|
class PortalFornecedorSuccessResponse(BaseModel):
|
||||||
|
success: bool = True
|
||||||
|
message: str
|
||||||
|
processInstanceId: str = ""
|
||||||
|
content: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
class PortalFornecedorErrorDetail(BaseModel):
|
||||||
|
message: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def env(name: str, default: str = "") -> str:
|
||||||
|
value = os.getenv(name, default).strip()
|
||||||
|
if not value:
|
||||||
|
raise RuntimeError(f"Missing environment variable: {name}")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI(title="Portal Fornecedor Proxy")
|
||||||
|
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=os.getenv("PORTAL_FORNECEDOR_CORS_ORIGINS", "*").split(","),
|
||||||
|
allow_credentials=False,
|
||||||
|
allow_methods=["POST", "OPTIONS", "GET"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health() -> dict[str, str]:
|
||||||
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post(
|
||||||
|
"/api/public/portalfornecedor/enviar",
|
||||||
|
response_model=PortalFornecedorSuccessResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": PortalFornecedorErrorDetail},
|
||||||
|
401: {"model": PortalFornecedorErrorDetail},
|
||||||
|
500: {"model": PortalFornecedorErrorDetail},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
async def enviar(
|
||||||
|
arquivo: UploadFile = File(...),
|
||||||
|
targetState: int = Form(5),
|
||||||
|
comment: str = Form("Envio via portal fornecedor"),
|
||||||
|
data_abertura: str = Form(...),
|
||||||
|
emitido_por: str = Form(...),
|
||||||
|
entidade_responsavel: str = Form(...),
|
||||||
|
tipo_cadastro: str = Form(...),
|
||||||
|
emailSolicitante: str = Form(""),
|
||||||
|
cpf: str = Form(...),
|
||||||
|
tipo_documento: str = Form(""),
|
||||||
|
numero_documento: str = Form(...),
|
||||||
|
valor: str = Form(""),
|
||||||
|
justificativa: str = Form(...),
|
||||||
|
) -> PortalFornecedorSuccessResponse:
|
||||||
|
file_name = arquivo.filename or "anexo"
|
||||||
|
file_mime = arquivo.content_type or "application/octet-stream"
|
||||||
|
file_bytes = await arquivo.read()
|
||||||
|
|
||||||
|
if not file_bytes:
|
||||||
|
raise HTTPException(status_code=400, detail={"message": "Arquivo obrigatorio."})
|
||||||
|
|
||||||
|
auth = build_auth()
|
||||||
|
upload_binary(file_name, file_bytes, auth)
|
||||||
|
document_id = create_document(file_name, file_mime, auth)
|
||||||
|
|
||||||
|
process_payload = {
|
||||||
|
"targetState": targetState,
|
||||||
|
"comment": comment,
|
||||||
|
"formFields": {
|
||||||
|
"data_abertura": data_abertura,
|
||||||
|
"emitido_por": emitido_por,
|
||||||
|
"entidade_responsavel": entidade_responsavel,
|
||||||
|
"tipo_cadastro": tipo_cadastro,
|
||||||
|
"emailSolicitante": emailSolicitante,
|
||||||
|
"cpf": cpf,
|
||||||
|
"tipo_documento": tipo_documento,
|
||||||
|
"numero_documento": numero_documento,
|
||||||
|
"valor": valor,
|
||||||
|
"justificativa": justificativa,
|
||||||
|
"anexo_documento_id": str(document_id),
|
||||||
|
"anexo_documento_nome": file_name,
|
||||||
|
"anexo_documento_mime": file_mime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
process_start_endpoint(),
|
||||||
|
json=process_payload,
|
||||||
|
auth=auth,
|
||||||
|
headers={"Accept": "application/json"},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not response.ok:
|
||||||
|
raise HTTPException(status_code=response.status_code, detail=safe_json(response))
|
||||||
|
|
||||||
|
data = safe_json(response)
|
||||||
|
|
||||||
|
return PortalFornecedorSuccessResponse(
|
||||||
|
success=True,
|
||||||
|
message="Solicitacao enviada com sucesso.",
|
||||||
|
processInstanceId=extract_process_instance_id(data),
|
||||||
|
content=data,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_auth() -> OAuth1:
|
||||||
|
return OAuth1(
|
||||||
|
client_key=env("PORTAL_FORNECEDOR_CLIENT_KEY"),
|
||||||
|
client_secret=env("PORTAL_FORNECEDOR_CLIENT_SECRET"),
|
||||||
|
resource_owner_key=env("PORTAL_FORNECEDOR_RESOURCE_OWNER_KEY"),
|
||||||
|
resource_owner_secret=env("PORTAL_FORNECEDOR_RESOURCE_OWNER_SECRET"),
|
||||||
|
signature_method="HMAC-SHA1",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def base_url() -> str:
|
||||||
|
return env("PORTAL_FORNECEDOR_BASE_URL").rstrip("/")
|
||||||
|
|
||||||
|
|
||||||
|
def process_start_endpoint() -> str:
|
||||||
|
process_id = env("PORTAL_FORNECEDOR_PROCESS_ID", "FlowEssentials_LancamentodeDocumento")
|
||||||
|
return f"{base_url()}/process-management/api/v2/processes/{process_id}/start"
|
||||||
|
|
||||||
|
|
||||||
|
def upload_binary(file_name: str, file_bytes: bytes, auth: OAuth1) -> None:
|
||||||
|
response = requests.post(
|
||||||
|
f"{base_url()}/api/public/2.0/contentfiles/upload/",
|
||||||
|
params={"fileName": file_name},
|
||||||
|
data=file_bytes,
|
||||||
|
auth=auth,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/octet-stream",
|
||||||
|
"Accept": "application/json",
|
||||||
|
},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not response.ok:
|
||||||
|
raise HTTPException(status_code=response.status_code, detail=safe_json(response))
|
||||||
|
|
||||||
|
|
||||||
|
def create_document(file_name: str, mime_type: str, auth: OAuth1) -> str:
|
||||||
|
payload = {
|
||||||
|
"companyId": env("PORTAL_FORNECEDOR_COMPANY_ID", "1"),
|
||||||
|
"description": file_name,
|
||||||
|
"parentId": int(env("PORTAL_FORNECEDOR_PARENT_FOLDER_ID", "10")),
|
||||||
|
"immutable": True,
|
||||||
|
"isPrivate": False,
|
||||||
|
"downloadEnabled": True,
|
||||||
|
"attachments": [{"fileName": file_name}],
|
||||||
|
"additionalComments": mime_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
f"{base_url()}/api/public/ecm/document/createDocument",
|
||||||
|
json=payload,
|
||||||
|
auth=auth,
|
||||||
|
headers={"Accept": "application/json"},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not response.ok:
|
||||||
|
raise HTTPException(status_code=response.status_code, detail=safe_json(response))
|
||||||
|
|
||||||
|
data = safe_json(response)
|
||||||
|
content = data.get("content", {}) if isinstance(data, dict) else {}
|
||||||
|
document_id = content.get("id") or content.get("documentId")
|
||||||
|
|
||||||
|
if not document_id:
|
||||||
|
raise HTTPException(status_code=500, detail={"message": "Fluig nao retornou documentId do anexo."})
|
||||||
|
|
||||||
|
return str(document_id)
|
||||||
|
|
||||||
|
|
||||||
|
def safe_json(response: requests.Response) -> Any:
|
||||||
|
try:
|
||||||
|
return response.json()
|
||||||
|
except Exception:
|
||||||
|
return {"message": response.text}
|
||||||
|
|
||||||
|
|
||||||
|
def extract_process_instance_id(data: Any) -> str:
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return ""
|
||||||
|
if data.get("processInstanceId"):
|
||||||
|
return str(data["processInstanceId"])
|
||||||
|
|
||||||
|
content = data.get("content")
|
||||||
|
if isinstance(content, dict):
|
||||||
|
if content.get("processInstanceId"):
|
||||||
|
return str(content["processInstanceId"])
|
||||||
|
if content.get("processInstanceid"):
|
||||||
|
return str(content["processInstanceid"])
|
||||||
|
if content.get("requestNumber"):
|
||||||
|
return str(content["requestNumber"])
|
||||||
|
|
||||||
|
return ""
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
fastapi==0.115.12
|
||||||
|
uvicorn==0.34.0
|
||||||
|
requests==2.32.3
|
||||||
|
requests-oauthlib==2.0.0
|
||||||
|
python-multipart==0.0.20
|
||||||
@ -1,4 +1,4 @@
|
|||||||
<div id="MyWidget_${instanceId}" class="super-widget wcm-widget-class fluig-style-guide"
|
<div id="MyWidget_${instanceId}" class="super-widget wcm-widget-class fluig-style-guide"
|
||||||
data-params="MyWidget.instance()">
|
data-params="MyWidget.instance()">
|
||||||
|
|
||||||
<link rel="stylesheet" href="/style-guide/css/fluig-style-guide.min.css">
|
<link rel="stylesheet" href="/style-guide/css/fluig-style-guide.min.css">
|
||||||
@ -102,6 +102,32 @@ data-params="MyWidget.instance()">
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="form-group col-md-12 alertaCampo">
|
||||||
|
|
||||||
|
<label>Anexar documento <strong class="text-danger">*</strong></label>
|
||||||
|
|
||||||
|
<p class="text-muted">
|
||||||
|
Selecione o arquivo ou use a camera do celular para capturar o documento.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-primary btn-anexo" id="anexaDocumento">
|
||||||
|
<i class="flaticon flaticon-paperclip"></i>
|
||||||
|
Anexar documento
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<input type="file"
|
||||||
|
id="arquivoLocal"
|
||||||
|
style="display:none"
|
||||||
|
accept="image/*,.pdf">
|
||||||
|
|
||||||
|
<div id="arquivoLocalNome" class="arquivo-nome"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="form-group col-md-6 alertaCampo">
|
<div class="form-group col-md-6 alertaCampo">
|
||||||
@ -131,29 +157,6 @@ data-params="MyWidget.instance()">
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="form-group col-md-12">
|
|
||||||
|
|
||||||
<label>Anexar documento <strong class="text-danger">*</strong></label>
|
|
||||||
|
|
||||||
<p class="text-muted">
|
|
||||||
Utilize o botão abaixo para anexar o documento.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-primary btn-anexo" id="anexaDocumento">
|
|
||||||
<i class="flaticon flaticon-paperclip"></i>
|
|
||||||
Anexar documento
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<input type="file" id="arquivoLocal" style="display:none">
|
|
||||||
|
|
||||||
<div id="arquivoLocalNome" class="arquivo-nome"></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-card">
|
<div class="form-card">
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
window.WCMAPI = window.WCMAPI || {};
|
window.WCMAPI = window.WCMAPI || {};
|
||||||
if (typeof window.WCMAPI.isMobileAppMode !== "function") {
|
if (typeof window.WCMAPI.isMobileAppMode !== "function") {
|
||||||
window.WCMAPI.isMobileAppMode = function () { return false; };
|
window.WCMAPI.isMobileAppMode = function () { return false; };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showCamera(param) {
|
function showCamera(param) {
|
||||||
if (typeof JSInterface !== "undefined" && JSInterface && typeof JSInterface.showCamera === "function") {
|
if (typeof JSInterface !== "undefined" && JSInterface && typeof JSInterface.showCamera === "function") {
|
||||||
JSInterface.showCamera(param);
|
JSInterface.showCamera(param);
|
||||||
@ -16,7 +17,6 @@ var MyWidget = SuperWidget.extend({
|
|||||||
init: function () {
|
init: function () {
|
||||||
this.root = $("#MyWidget_" + this.instanceId);
|
this.root = $("#MyWidget_" + this.instanceId);
|
||||||
this.anexoInfo = null;
|
this.anexoInfo = null;
|
||||||
this.gedParentFolderId = 10;
|
|
||||||
this.isSending = false;
|
this.isSending = false;
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
this.setupInitialValues();
|
this.setupInitialValues();
|
||||||
@ -29,11 +29,11 @@ var MyWidget = SuperWidget.extend({
|
|||||||
self.enviarDocumento();
|
self.enviarDocumento();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.root.find("#anexaDocumento").off("click").on("click", function () {
|
this.root.find("#anexaDocumento_" + this.instanceId + ", #anexaDocumento").off("click").on("click", function () {
|
||||||
self.handleAnexo();
|
self.handleAnexo();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.root.find("#arquivoLocal").off("change").on("change", function () {
|
this.root.find("#arquivoLocal_" + this.instanceId + ", #arquivoLocal").off("change").on("change", function () {
|
||||||
self.onArquivoSelecionado(this);
|
self.onArquivoSelecionado(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -57,6 +57,7 @@ var MyWidget = SuperWidget.extend({
|
|||||||
this.root.find("#tipo_cadastro").val("cpf").trigger("change");
|
this.root.find("#tipo_cadastro").val("cpf").trigger("change");
|
||||||
this.root.find("#emitido_por").val("fornecedor");
|
this.root.find("#emitido_por").val("fornecedor");
|
||||||
this.root.find("#tipo_documento").val("danfe");
|
this.root.find("#tipo_documento").val("danfe");
|
||||||
|
this.root.find("#arquivoLocalNome").text("");
|
||||||
this.clearStatus();
|
this.clearStatus();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -78,48 +79,10 @@ var MyWidget = SuperWidget.extend({
|
|||||||
|
|
||||||
this.root.find("#arquivoLocalNome").text("Arquivo selecionado: " + file.name + " (" + this.formatFileSize(file.size || 0) + ")");
|
this.root.find("#arquivoLocalNome").text("Arquivo selecionado: " + file.name + " (" + this.formatFileSize(file.size || 0) + ")");
|
||||||
this.clearStatus();
|
this.clearStatus();
|
||||||
|
|
||||||
console.log("[portalfornecedor] anexo preparado para envio:", {
|
|
||||||
fileName: this.anexoInfo.fileName,
|
|
||||||
mimeType: this.anexoInfo.mimeType,
|
|
||||||
fileSize: this.anexoInfo.fileSize
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleAnexo: function () {
|
handleAnexo: function () {
|
||||||
if (showCamera("anexo_documento")) {
|
this.root.find("#arquivoLocal_" + this.instanceId + ", #arquivoLocal").trigger("click");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.openAttachmentTab()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.root.find("#arquivoLocal").trigger("click");
|
|
||||||
},
|
|
||||||
|
|
||||||
openAttachmentTab: function () {
|
|
||||||
try {
|
|
||||||
var parentDoc = window.parent && window.parent.document ? window.parent.document : document;
|
|
||||||
var selectors = [
|
|
||||||
"#tab-attachments",
|
|
||||||
"a[href*='attachments']",
|
|
||||||
"a[aria-controls*='attachments']",
|
|
||||||
"[data-tab*='attachments']"
|
|
||||||
];
|
|
||||||
|
|
||||||
for (var i = 0; i < selectors.length; i++) {
|
|
||||||
var el = parentDoc.querySelector(selectors[i]);
|
|
||||||
if (el) {
|
|
||||||
el.click();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleTipoCadastro: function (tipo) {
|
toggleTipoCadastro: function (tipo) {
|
||||||
@ -188,61 +151,44 @@ var MyWidget = SuperWidget.extend({
|
|||||||
|
|
||||||
this.setLoading(true, "Enviando documento, aguarde...");
|
this.setLoading(true, "Enviando documento, aguarde...");
|
||||||
|
|
||||||
this.uploadAnexoToECM(this.anexoInfo.file)
|
var payloadProcesso = {
|
||||||
.done(function (docData) {
|
targetState: 5,
|
||||||
var payloadProcesso = {
|
comment: "Envio via portal fornecedor",
|
||||||
targetState: 0,
|
formFields: {
|
||||||
subProcessTargetState: 0,
|
data_abertura: self.value("#data_abertura"),
|
||||||
comment: "Solicitacao criada via widget",
|
emitido_por: self.value("#emitido_por"),
|
||||||
formFields: {
|
entidade_responsavel: self.value("#entidade_responsavel"),
|
||||||
data_abertura: self.value("#data_abertura"),
|
tipo_cadastro: tipoCadastro,
|
||||||
emitido_por: self.value("#emitido_por"),
|
emailSolicitante: self.value("#emailSolicitante"),
|
||||||
entidade_responsavel: self.value("#entidade_responsavel"),
|
cpf: cpfField || documentoPessoa,
|
||||||
tipo_cadastro: tipoCadastro,
|
tipo_documento: self.value("#tipo_documento"),
|
||||||
emailSolicitante: self.value("#emailSolicitante"),
|
numero_documento: numeroDocumento,
|
||||||
cpf: cpfField || documentoPessoa,
|
valor: valor,
|
||||||
tipo_documento: self.value("#tipo_documento"),
|
justificativa: self.value("#justificativa")
|
||||||
numero_documento: numeroDocumento,
|
}
|
||||||
valor: valor,
|
};
|
||||||
justificativa: self.value("#justificativa"),
|
|
||||||
anexo_documento_id: String(docData.documentId || ""),
|
|
||||||
anexo_documento_nome: self.anexoInfo.fileName,
|
|
||||||
anexo_documento_mime: self.anexoInfo.mimeType
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.__portalfornecedor_lastProcessPayload = payloadProcesso;
|
window.__portalfornecedor_lastProcessPayload = payloadProcesso;
|
||||||
console.log("[portalfornecedor] payload direto processo:", payloadProcesso);
|
console.log("[portalfornecedor] payload endpoint:", payloadProcesso);
|
||||||
|
|
||||||
self.enviarDiretoProcesso(payloadProcesso)
|
this.enviarViaEndpoint(payloadProcesso, this.anexoInfo.file)
|
||||||
.done(function (response) {
|
.done(function (response) {
|
||||||
console.log("[portalfornecedor] response processo direto:", response);
|
console.log("[portalfornecedor] response endpoint:", response);
|
||||||
self.setLoading(false);
|
|
||||||
self.renderSuccessState(response);
|
|
||||||
})
|
|
||||||
.fail(function (xhrDireto) {
|
|
||||||
self.setLoading(false);
|
|
||||||
console.warn("[portalfornecedor] falha no envio direto:", xhrDireto);
|
|
||||||
console.error("[portalfornecedor] detalhe erro processo direto:", {
|
|
||||||
status: xhrDireto.status,
|
|
||||||
statusText: xhrDireto.statusText,
|
|
||||||
responseText: xhrDireto.responseText
|
|
||||||
});
|
|
||||||
self.setStatus("error", "Falha ao iniciar processo. Veja o console para detalhes.");
|
|
||||||
FLUIGC.toast({
|
|
||||||
title: "Erro",
|
|
||||||
message: "Falha ao iniciar processo. Veja o console para detalhes.",
|
|
||||||
type: "danger"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.fail(function (uploadErr) {
|
|
||||||
self.setLoading(false);
|
self.setLoading(false);
|
||||||
console.error("[portalfornecedor] falha upload documento ECM:", uploadErr);
|
self.renderSuccessState(response);
|
||||||
self.setStatus("error", "Falha ao enviar anexo para o GED.");
|
})
|
||||||
|
.fail(function (xhr) {
|
||||||
|
self.setLoading(false);
|
||||||
|
console.warn("[portalfornecedor] falha no envio via endpoint:", xhr);
|
||||||
|
console.error("[portalfornecedor] detalhe erro endpoint:", {
|
||||||
|
status: xhr.status,
|
||||||
|
statusText: xhr.statusText,
|
||||||
|
responseText: xhr.responseText
|
||||||
|
});
|
||||||
|
self.setStatus("error", self.extractEndpointErrorMessage(xhr));
|
||||||
FLUIGC.toast({
|
FLUIGC.toast({
|
||||||
title: "Erro",
|
title: "Erro",
|
||||||
message: "Falha ao enviar anexo para o GED.",
|
message: "Falha ao enviar pelo endpoint do portal.",
|
||||||
type: "danger"
|
type: "danger"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -270,67 +216,68 @@ var MyWidget = SuperWidget.extend({
|
|||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
|
|
||||||
enviarDiretoProcesso: function (payloadProcesso) {
|
enviarViaEndpoint: function (payloadProcesso, file) {
|
||||||
return $.ajax({
|
return $.ajax({
|
||||||
url: "/process-management/api/v2/processes/FlowEssentials_LancamentodeDocumento/start",
|
url: this.getPublicEndpointUrl(),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: "application/json",
|
data: this.buildMultipartData(payloadProcesso, file),
|
||||||
data: JSON.stringify(payloadProcesso)
|
processData: false,
|
||||||
|
contentType: false
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
uploadAnexoToECM: function (file) {
|
getPublicEndpointUrl: function () {
|
||||||
var self = this;
|
if (window.portalfornecedorConfig && window.portalfornecedorConfig.publicEndpointUrl) {
|
||||||
var dfd = $.Deferred();
|
return window.portalfornecedorConfig.publicEndpointUrl;
|
||||||
var fileName = file.name;
|
}
|
||||||
var uploadUrl = "/api/public/2.0/contentfiles/upload/?fileName=" + encodeURIComponent(fileName);
|
|
||||||
|
|
||||||
fetch(uploadUrl, {
|
return "https://api.grupoginseng.com.br/v2/api/public/portalfornecedor/enviar";
|
||||||
method: "POST",
|
},
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/octet-stream"
|
|
||||||
},
|
|
||||||
body: file
|
|
||||||
})
|
|
||||||
.then(function (resp) {
|
|
||||||
if (!resp.ok) throw new Error("Falha no upload binario");
|
|
||||||
return resp.text();
|
|
||||||
})
|
|
||||||
.then(function () {
|
|
||||||
var companyId = (window.WCMAPI && WCMAPI.organizationId) ? String(WCMAPI.organizationId) : "1";
|
|
||||||
var createPayload = {
|
|
||||||
companyId: companyId,
|
|
||||||
description: fileName,
|
|
||||||
parentId: self.gedParentFolderId,
|
|
||||||
immutable: true,
|
|
||||||
isPrivate: false,
|
|
||||||
downloadEnabled: true,
|
|
||||||
attachments: [{ fileName: fileName }]
|
|
||||||
};
|
|
||||||
|
|
||||||
return fetch("/api/public/ecm/document/createDocument", {
|
buildMultipartData: function (payloadProcesso, file) {
|
||||||
method: "POST",
|
var formData = new FormData();
|
||||||
headers: {
|
var formFields = payloadProcesso && payloadProcesso.formFields ? payloadProcesso.formFields : {};
|
||||||
"Content-Type": "application/json;charset=utf-8"
|
var keys = Object.keys(formFields);
|
||||||
},
|
|
||||||
body: JSON.stringify(createPayload)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(function (resp) {
|
|
||||||
if (!resp.ok) throw new Error("Falha ao criar documento no GED");
|
|
||||||
return resp.json();
|
|
||||||
})
|
|
||||||
.then(function (data) {
|
|
||||||
var content = data && data.content ? data.content : {};
|
|
||||||
var documentId = content.id || content.documentId;
|
|
||||||
if (!documentId) throw new Error("GED nao retornou documentId");
|
|
||||||
dfd.resolve({ documentId: documentId, raw: data });
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
dfd.reject(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
return dfd.promise();
|
formData.append("targetState", String(payloadProcesso.targetState || 5));
|
||||||
|
formData.append("comment", payloadProcesso.comment || "");
|
||||||
|
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
formData.append(key, formFields[key] == null ? "" : String(formFields[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
formData.append("arquivo", file, file.name || "anexo");
|
||||||
|
}
|
||||||
|
|
||||||
|
return formData;
|
||||||
|
},
|
||||||
|
|
||||||
|
extractEndpointErrorMessage: function (xhr) {
|
||||||
|
if (!xhr || !xhr.responseText) {
|
||||||
|
return "Falha ao enviar pelo endpoint do portal. Veja o console para detalhes.";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var payload = JSON.parse(xhr.responseText);
|
||||||
|
if (payload && payload.message) {
|
||||||
|
return String(payload.message);
|
||||||
|
}
|
||||||
|
if (payload && payload.detail && typeof payload.detail === "string") {
|
||||||
|
return String(payload.detail);
|
||||||
|
}
|
||||||
|
if (payload && payload.detail && payload.detail.message) {
|
||||||
|
return String(payload.detail.message);
|
||||||
|
}
|
||||||
|
if (payload && payload.detailedMessage) {
|
||||||
|
return String(payload.detailedMessage);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return xhr.responseText;
|
||||||
},
|
},
|
||||||
|
|
||||||
setLoading: function (isLoading, message) {
|
setLoading: function (isLoading, message) {
|
||||||
@ -379,6 +326,8 @@ var MyWidget = SuperWidget.extend({
|
|||||||
this.clearFieldError("#cpf");
|
this.clearFieldError("#cpf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.anexoInfo || !this.anexoInfo.file) ok = this.markRequired("#arquivoLocal") && ok;
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -457,4 +406,3 @@ var MyWidget = SuperWidget.extend({
|
|||||||
return (b / 1048576).toFixed(2) + " MB";
|
return (b / 1048576).toFixed(2) + " MB";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user