Na pasta NotaFiscal/Nfe crie um arquivo chamado TabProduto.blade.php em seguida copie o conteúdo do arquivo TabProduto do layout baixado e cole na view criada
Na view Edit, faça os seguintes procedimentos:
- Faça o loop para receber os dados do banco e listar os itens da nota
@php
$j = 1;
@endphp
@foreach ($itens as $item)
<tr>
<td align="left">{{ $j++ }} </td>
<td align="left">{{ $item->xProd }} </td>
<td align="center">{{ $item->vUnCom }} </td>
<td align="center">{{ $item->qCom }} </td>
<td align="center">{{ $item->vProd }} </td>
<td align="center">{{ $item->NCM }} </td>
<td align="center">{{ $item->CFOP }} </td>
<td align="center">{{ $item->vICMS ? $item->vICMS : 0 }} </td>
<td align="center">{{ $item->vIPI ? $item->vIPI : 0 }} </td>
<td align="center">{{ $item->vPIS ? $item->vPIS : 0 }} </td>
<td align="center">{{ $item->vCOFINS ? $item->vCOFINS : 0 }} </td>
<td align="center"><a href="javascript:;"
onclick="verDetalheItemNfe({{ $item->id }})"
class="btn btn-outline-azul d-inline-block btn-pequeno fas fa-eye"
title="Detalhes"> </a></td>
<td align="center"><a href='javascript:;'
onclick='excluirProduto({{ $item->id }})'
class='btn btn-outline-vermelho btn-pequeno fas fa-trash' title='Excluir'></a>
</td>
</tr>
@endforeach
Caso não tenha criado crie uma função para buscar os produtos via jquery
Para o componente produto crie um método que deverá ser disparado no evento keyup, este método deverá fazer uma consulta no banco via jquery, passando como parâmetro o texto a ser pesquisado e deverá a lista de produtos que contenha o respectivo texto, em seguida deverá mostrar essa lista em uma div abaixo do componente no qual foi digitado o texto.
Ao clicar em um dos itens da lista deverá popular os componentes nome, preco e produto_id com os respectivos valor e fechar a lista, assim como também chamar o método calcularDescontoItem que deverá ser implementado a seguir
$("#produto").on("keyup", function(){
var q = $("#produto").val();
$.ajax({
url: base_url + "produto/pesquisa/",
type: "get",
data: {
q:q
},
dataType:"Json",
success: function(data){
$("#produto").after('<div class="listaProdutos"></div>');
var html = "<ul>";
for(var i in data){
html += '<li class="si"><a href="javascript:;" onclick="selecionarProduto(this)" '+
'data-id="'+data[i].id +
'" data-preco = "' + data[i].preco_venda +
'" data-nome = "' + data[i].produto +
'" data-unidade = "' + data[i].unidade + '">' +
data[i].nome + ' - ' + data[i].preco_venda +'</a></li>';
}
html +="</ul>";
$(".listaProdutos").html(html);
$(".listaProdutos").show();
}
});
})
});
function selecionarProduto(obj){
var id = $(obj).attr("data-id");
var nome = $(obj).attr("data-nome");
var preco = $(obj).attr("data-preco");
$(".listaProdutos").hide();
$("#id_produto").val(id);
$("#produto").val(nome);
$("#preco").val(converteFloatMoeda(preco));
$("#subtotal").val(converteFloatMoeda(preco));
$("#total_item").val(converteFloatMoeda(preco));
$("#qtde").val(1);
$("#qtde").focus();
}
No arquivo js_venda.js crie um método chamado calcularDescontoItem, o qual deverá:
- receba os valores: quantidade, preco, desconto_por_valor, desconto_percentual
- Se a o desconto percentual for maior que zerto, então o desconto_por_unidade será igual ao preco vezes desconto_percentual vezes 0.01
- Se o desconto_por_valor for maior que zero, então desconto_por_unidade é igual ao desconto_por_valor
- subtotal_liquido é igual (preco - desconto_por_unidade) vezes quantidade
- total_desconto_item é igual desconto_por_unidade vezes quantidade
function calcSubtotal() {
let qtde = converteMoedaFloat($('#qtde').val());
let preco = converteMoedaFloat($('#preco').val());
let subtotal = preco * qtde;
$('#subtotal').val(converteFloatMoeda(subtotal.toFixed(2)));
$('#total_item').val(converteFloatMoeda(subtotal));
calcularDescontoItem();
}
function calcularDescontoItem(){
let tipo_desc = $('#tipo_desc').val();
let qtde = converteMoedaFloat($('#qtde').val());
let preco = converteMoedaFloat($('#preco').val());
let subtotal = converteMoedaFloat($('#subtotal').val());
let val_desconto= converteMoedaFloat($('#val_desconto').val());
var desc = parseFloat(0);
var desconto = parseFloat(0);
if(tipo_desc=="desc_perc"){
desconto = qtde * preco * val_desconto * 0.01 ;
}else if(tipo_desc=="desc_valor"){
desconto = qtde * val_desconto
}
desc = subtotal - desconto;
$('#desconto').val(converteFloatMoeda(desconto));
$('#total_item').val(converteFloatMoeda(desc));
}
para o componente quantidade, val_desconto, desconto_percentual e desconto_por_valor no método keyup chame o método calcularDescontoItem();
para o campo val_desconto, no evento blur, faça uma verificação se o valor é null ou vazio, caso seja atribua o valor zero e em seguida chame o método calcularDescontoItem
$('#preco').on('keyup', () => {
calcSubtotal()
})
$('#qtde').on('keyup', () => {
calcSubtotal()
})
$('#val_desconto').on('keyup', () => {
calcularDescontoItem();
})
$('#val_desconto').on('blur', () => {
let val_desconto= $('#val_desconto').val();
if(val_desconto==null || val_desconto=='' ){
$('#val_desconto').val(0);
}
calcularDescontoItem();
})
$('#desconto_percentual').on('keyup', () => {
$('#desconto_por_valor').val(0);
calcularDescontoItem();
})
$('#desconto_por_valor').on('keyup', () => {
$('#desconto_percentual').val(0);
calcularDescontoItem()
})
No arquivo tabProduto_js.js crie um método chamado btnInserirProduto, o que deverá invocar a rota store do controller ItemController e enviar como parâmetros o nfe_id, natureza_operacao_id , qtde, preco, desconto_percentual, desconto_por_valor e caso não retorne nenhum erro , liste os itens da nota.
$("#btnInserirProduto").on("click", function(){
var id_produto = $("#id_produto").val();
var qtde = converteMoedaFloat($("#qtde").val());
var preco = converteMoedaFloat($("#preco").val());
var tipo_desc = $("#tipo_desc").val();
let valor_desconto = converteMoedaFloat($('#val_desconto').val());
let desconto_percentual = 0;
let desconto_por_valor = 0;
if(id_produto == ''){
$("#mostrarUmErro").html(MostrarUmaMsgErro("Selecione um Produto primeiramente"));
return false;
}
if(parseFloat(qtde <= 0)){
$("#mostrarUmErro").html(MostrarUmaMsgErro("Digite a quantidade primeiramente"));
return false;
}
if(qtde.length <= 0 && parseFloat(qtde <= 0) ){
$("#mostrarUmErro").html(MostrarUmaMsgErro("Digite a quantidade primeiramente"));
return false;
}
if(Number.isNaN(qtde)){
$("#mostrarUmErro").html(MostrarUmaMsgErro("Digite a quantidade primeiramente"));
return false;
}
if(Number.isNaN(preco)){
$("#mostrarUmErro").html(MostrarUmaMsgErro("Digite a Valor primeiramente"));
return false;
}
if(valor_desconto > 0){
if(tipo_desc=="desc_perc"){
desconto_percentual = valor_desconto;
desconto_por_valor = 0;
}
if(tipo_desc=="desc_valor"){
desconto_percentual = 0;
desconto_por_valor = valor_desconto;
}
}
$.ajax({
url: base_url + "itemnotafiscal",
type: "POST",
data: {
nfe_id:nfe_id,
natureza_operacao_id : natureza_operacao_id ,
produto_id: id_produto,
qtde:qtde,
preco:preco ,
desconto_percentual : desconto_percentual,
desconto_por_valor: desconto_por_valor
},
dataType:"Json",
success: function(data){
fecharModal();
if(data.tem_erro ==true){
$("#mostrarUmErro").html(MostrarUmaMsgErro(" Erro: " + data.erro));
}else{
lista_itens(data.itens);
limparDadosItem();
}
}, error: function (e) {
fecharModal();
var response = JSON.parse(e.responseText);
$("#mostrarErros").html(MostrarMsgErros(response.errors));
}
});
});
No arquivo tabProduto_js crie um método chamado lista_ites, o qual deverá receber a lista de produtos da nota e mostrar no componente tabela
function lista_itens(data){
var html = "";
var j = 1;
for(var i in data){
var vIcms = (data[i].vICMS != null) ? data[i].vICMS : 0;
var vIpi = (data[i].vIPI != null) ? data[i].vIPI : 0;
var vPis = (data[i].vPIS != null) ? data[i].vPIS : 0;
var vCofins = (data[i].vCOFINS != null) ? data[i].vCOFINS : 0;
html += "<tr> " +
"<td>" + j++ + "</td>" +
"<td>" + data[i].xProd + "</td>" +
"<td>" + data[i].vUnCom+ "</td>" +
"<td>" + data[i].qCom+ "</td>" +
"<td>" + data[i].vProd+ "</td>" +
"<td>" + data[i].NCM+ "</td>" +
"<td>" + data[i].CFOP+ "</td>" +
"<td>" + vIcms + "</td>" +
"<td>" + vIpi + "</td>" +
"<td>" + vPis + "</td>" +
"<td>" + vCofins + "</td>" +
"<td><a href='javascript:;' onclick='verDetalheItemNfe("+ data[i].id +")' class='btn btn-outline-verde btn-pequeno'>Detalhes</a></td>" +
"<td><a href='javascript:;' onclick='excluirProduto("+ data[i].id +")' class='btn btn-outline-vermelho btn-pequeno' title='Excluir'>Excluir</a></td>" +
"</tr>";
}
$("#lista_itens").html(html);
}
Crie um controller de recursos chamado ItemNotaFiscalController, para criar o controller use o comando: php artisan make:controller \NotaFiscal\ItemNotaFiscalController -r
modifique o método store do controller ItemNotaFiscalController, este método deverá:
- Receber os dados do formulário
- Criar um objeto do tipo stdClass para receber os dados vindos do formulário;
- fazer as convenções dos dados decimais para o padrão do mysql
- Calcular o desconto_por_unidade
- Calcular o total_desconto_item
- Calcular o subtotal_liquido
- Salvar os dados no banco
- Retornar a lista de Itens da Nota
$req = $request->except(["_token","_method"]);
$retorno = new \stdClass();
try {
$dados = new \stdClass();
$preco = $req["preco"] ? getFloat($req["preco"]) : 0;
$dados->nfe_id = $req["nfe_id"];
$dados->cProd = $req["produto_id"];
$dados->produto_id = $req["produto_id"];
$dados->qCom = $req["qtde"] ? getFloat($req["qtde"]) : 0;
$dados->vProd = $dados->qCom * $preco;
$dados->preco_original = $preco;
$dados->desconto_por_valor = $req["desconto_por_valor"] ? getFloat($req["desconto_por_valor"]) : 0;
$dados->desconto_percentual = $req["desconto_percentual"] ? getFloat($req["desconto_percentual"]) : 0;
$dados->desconto_por_unidade = 0;
if($dados->desconto_por_valor > 0){
$dados->desconto_por_unidade = $dados->desconto_por_valor;
}
if($dados->desconto_percentual > 0){
$dados->desconto_por_unidade = $dados->desconto_percentual * $preco * 0.01;
}
$dados->total_desconto_item = $dados->desconto_por_unidade * $dados->qCom;
$dados->subtotal_liquido = ($preco - $dados->desconto_por_unidade ) * $dados->qCom;
$dados->vProd = $dados->qCom * $preco - ($dados->desconto_por_unidade * $dados->qCom) ;
$dados->vUnCom = $preco - $dados->desconto_por_unidade;
NfeItem::Create(objToArray($dados));
$lista = NfeItem::where("nfe_id",$dados->nfe_id)->get();
$retorno->tem_erro = false;
$retorno->erro = "";
$retorno->nfe = Nfe::find($dados->nfe_id);
$retorno->itens = $lista;
return response()->json($retorno);
} catch (\Exception $e) {
$retorno->tem_erro = true;
$retorno->erro = $e->getMessage();
$retorno->retorno = "";
return response()->json($retorno);
}
No arquivo tabProduto_js crie um método chamar excluirProduto, o qual deverá excluir um item via ajax.
function excluirProduto(id){
$.ajax({
url: base_url + "itemnotafiscal/" + id ,
type: "DELETE",
data: { },
dataType:"Json",
success: function(data){
if(data.tem_erro ==true){
$("#mostrarUmErro").html(MostrarUmaMsgErro(" Erro: " + data.erro));
}else{
lista_itens(data.itens);
}
}
});
}
implemente o método destroy do ItemNotaFiscalController, com as seguinte ações:
- Busque o item pelo id passado no parâmetro
- Caso encontre, exclua a mesma do banco, coloque esta instrução em um bloco try/catch
- redirecione para a rota index
$retorno = new \stdClass();
try {
$item = NfeItem::find($id);
if($item){
$item->delete();
}
$lista = NfeItem::where("nfe_id",$item->nfe_id)->get();
$retorno->tem_erro = false;
$retorno->erro = "";
$retorno->nfe = Nfe::find($item->nfe_id);
$retorno->itens = $lista;
return response()->json($retorno);
} catch (\Exception $e) {
$retorno->tem_erro = true;
$retorno->erro = $e->getMessage();
$retorno->retorno = "";
return response()->json($retorno);
}
Crie um observer para o model ItemNotaFiscal, para isso use o comando: php artisan make:observer ItemNotaFiscalObserver
Crie um método creating, que receberá como parâmetro um objeto do tipo NfeItem, o qual deverá:
- Buscar o produto, a nfe e a tributação
- popular os campos da tabela ItemNotaFiscal com os dados do produto
- popular os dados dos impostos
public function creating(NfeItem $item){
$produto = Produto::find($item->cProd);
$nfe = Nfe::find($item->nfe_id);
$tributacao = Tributacao::first();
$item->cEAN = ($produto->gtin) ? $produto->gtin :"SEM GTIN";
$item->xProd = tiraAcento($produto->nome);
$item->NCM = tira_mascara($produto->ncm);
$item->cBenef = $produto->cbenef; //incluido no layout 4.00
$item->EXTIPI = $produto->tipi;
$item->CEST = $produto->cest;
$item->uCom = tiraAcento($produto->unidade);
$item->cEANTrib = ($produto->gtin) ? $produto->gtin :"SEM GTIN";
$item->xPed = $item->nfe_id ;
$item->uTrib = tiraAcento($produto->unidade);
$item->qTrib = $item->qCom;
$item->vUnTrib = $item->vUnCom;
$item->indTot = 1;
//Buscar o CFOP
$item->CFOP = $tributacao->cfop;;
//Definindo a Alíquota do ICMS
$cstIcms = $tributacao->cstICMS;
$pICMS = $tributacao->pICMS;
//Verificação do IVA para Cálculo da Substituição Tributária
$pICMSST = null;
//Atribuindo valores
$item->orig = $produto->origem ;
$item->cstICMS = $cstIcms;
$item->modBC = $tributacao->modBC;
$item->pRedBC = $tributacao->pRedBC;
$item->vBCICMS = $item->vProd + $item->vOutro + $item->vSeg + $item->vFrete;
$item->pICMS = $pICMS;
$item->modBCST = null;
$item->valor_pauta = null ;
$item->qtde_pauta = $item->quantidade;
$item->pMVAST = null;
$item->pRedBCST = null;
$item->pICMSST = $pICMSST;
$item->pBCop = $tributacao->pBCOp;
$item->UFST = $tributacao->UFST;
$item->motDesICMS = $tributacao->motDesICMS;
$item->pCredSN = $nfe->em_pCredSN;
$item->pDif = null;
$item->vBCFCP = $item->vBCICMS;
$item->pFCP = $tributacao->pFCP;
$item->pFCPST = null;
$item->vBCSTRet = $tributacao->vBCSTRet;
$item->vICMSSTRet = $tributacao->vICMSSTRet;
$item->vBCSTDest = $tributacao->vBCSTDest;
$item->vICMSSTDest = $tributacao->vICMSSTDest;
$item->vBCFCPSTRet = $tributacao->vBCFCPSTRet;
$item->pFCPSTRet = $tributacao->pFCPSTRet;
$item->vFCPSTRet = $tributacao->vFCPSTRet;
//Cálculo do IPI
$item->cstIPI = $tributacao->cstIPI;
$item->tipo_calc_ipi = $tributacao->tipo_calc_ipi;
$item->CNPJProd = $tributacao->CNPJProd;
$item->cSelo = $tributacao->cSelo;
$item->qSelo = $tributacao->qSelo;
$item->cEnq = $tributacao->cEnq ? $tributacao->cEnq : "999" ;
$item->vBCIPI = $item->vProd + $item->vOutro + $item->vSeg + $item->vFrete;
$item->pIPI = $tributacao->pIPI;
$item->qUnidIPI = $tributacao->qUnidIPI;
$item->vUnidIPI = $tributacao->vUnidIPI;
//Cálculo Pis
$item->cstPIS = $tributacao->cstPIS ;
$item->vBCPIS = $item->vProd + $item->vOutro + $item->vSeg + $item->vFrete -$item->vDesc;
$item->pPIS = $tributacao->pPIS;
$item->qBCProdPis = $tributacao->qBCProd_pis;
$item->vAliqProd_pis = $tributacao->vAliqProd_pis;
$item->tipo_calc_pis = $tributacao->tipo_calc_pis;
//Cálculo Cofins
$item->cstCOFINS = $tributacao->cstCOFINS ;
$item->vBCCOFINS = $item->vProd + $item->vOutro + $item->vSeg + $item->vFrete -$item->vDesc;
$item->pCOFINS = $tributacao->pCOFINS;
$item->qBCProdConfis = $tributacao->qBCProdConfis;
$item->vAliqProd_cofins = $tributacao->vAliqProd_cofins;
$item->tipo_calc_cofins = $tributacao->tipo_calc_cofins;
}
Crie um método created o qual deverá receber um NfeItem como parâmetro e atualizar todos os totais da Nfe
public function created(NfeItem $item){
$itens = NfeItem::where("nfe_id",$item->nfe_id);
$nfe = Nfe::find($item->nfe_id);
$total_itens = $itens->sum("vProd");
$nfe->vProd = $total_itens;
$nfe->vFCP = $itens->sum("vFCP");
$nfe->vIPI = $itens->sum("vIPI");
$nfe->vPIS = $itens->sum("vPIS");
$nfe->vCOFINS = $itens->sum("vCOFINS");
$nfe->vBCST = $itens->sum("vBCST");
$nfe->vST = $itens->sum("vICMSST");
$nfe->vNF = $nfe->vProd - $nfe->vDesc + $nfe->vST + $nfe->vFrete + $nfe->vSeg + $nfe->vOutro + $nfe->vII + $nfe->vIPI + $nfe->vServ;
$nfe->vOrig = $nfe->vNF;
$nfe->vLiq = $nfe->vOrig ;
$nfe->estadual = $itens->sum("estadual");
$nfe->municipal = $itens->sum("municipal");
$nfe->nacionalfederal = $itens->sum("nacionalfederal");
$nfe->vTotTrib = $itens->sum("vTotTrib");
$nfe->vBC = $itens->sum("vBCICMS");
$nfe->vICMS = $itens->sum("vICMS");
$nfe->save();
}