teste #3
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 292 KiB After Width: | Height: | Size: 292 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
BIN
Imagens para correção /BKP/Imagem colada.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 75 KiB |
@@ -13,7 +13,7 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
def validar
|
def validar
|
||||||
authorize @consolidacao, :show?
|
authorize @consolidacao, :show?
|
||||||
@motorista = params[:motorista]
|
@motorista = params[:motorista]
|
||||||
@veiculo = params[:vehicle].presence # filtro "fechar por carro" (opcional)
|
@veiculos_sel = veiculos_param(params[:vehicle]) # filtro por veículo(s) — multi-seleção
|
||||||
|
|
||||||
# Entregas atendidas do período no banco existente (read-only): sucesso +
|
# Entregas atendidas do período no banco existente (read-only): sucesso +
|
||||||
# insucesso, pois o motorista foi ao local e a entrega precisa constar.
|
# insucesso, pois o motorista foi ao local e a entrega precisa constar.
|
||||||
@@ -24,7 +24,7 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
.do_motorista(@motorista)
|
.do_motorista(@motorista)
|
||||||
@entregas = @entregas.da_veiculo(@consolidacao.vehicle_ids) if @consolidacao.vehicle_ids.present?
|
@entregas = @entregas.da_veiculo(@consolidacao.vehicle_ids) if @consolidacao.vehicle_ids.present?
|
||||||
@entregas = @entregas.da_operacoes(@consolidacao.operacoes) if @consolidacao.operacoes.present?
|
@entregas = @entregas.da_operacoes(@consolidacao.operacoes) if @consolidacao.operacoes.present?
|
||||||
@entregas = filtrar_por_veiculo(@entregas, @veiculo) if @veiculo
|
@entregas = filtrar_por_veiculo(@entregas, @veiculos_sel) if @veiculos_sel.any?
|
||||||
@entregas = @entregas.order(:checkout)
|
@entregas = @entregas.order(:checkout)
|
||||||
|
|
||||||
# Classificações já feitas — agrupadas por tracking_id (uma entrega pode ter
|
# Classificações já feitas — agrupadas por tracking_id (uma entrega pode ter
|
||||||
@@ -36,10 +36,10 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
# Status "fechado" por veículo (filtro + acompanhamento) e totais com escopo:
|
# Status "fechado" por veículo (filtro + acompanhamento) e totais com escopo:
|
||||||
# quando um carro está selecionado, a barra reflete só aquele carro.
|
# quando um carro está selecionado, a barra reflete só aquele carro.
|
||||||
@veiculos_status = veiculos_status(@motorista)
|
@veiculos_status = veiculos_status(@motorista)
|
||||||
if @veiculo
|
if @veiculos_sel.any?
|
||||||
atual = @veiculos_status.find { |v| v[:vehicle] == @veiculo }
|
sel = @veiculos_status.select { |v| @veiculos_sel.include?(v[:vehicle]) }
|
||||||
@total_entregas = atual ? atual[:eligible] : 0
|
@total_entregas = sel.sum { |v| v[:eligible] }
|
||||||
@classificadas = atual ? atual[:classificadas] : 0
|
@classificadas = sel.sum { |v| v[:classificadas] }
|
||||||
else
|
else
|
||||||
@total_entregas = @consolidacao.entregas_elegiveis_count(@motorista)
|
@total_entregas = @consolidacao.entregas_elegiveis_count(@motorista)
|
||||||
@classificadas = @consolidacao.classificadas_count(@motorista)
|
@classificadas = @consolidacao.classificadas_count(@motorista)
|
||||||
@@ -97,7 +97,7 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
render json: resumo_json(params[:motorista], vehicle: params[:vehicle].presence).merge(
|
render json: resumo_json(params[:motorista], vehicles: params[:vehicle]).merge(
|
||||||
ativo: ativo, tracking_id: params[:tracking_id], tipo: params[:tipo]
|
ativo: ativo, tracking_id: params[:tracking_id], tipo: params[:tipo]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@@ -116,8 +116,8 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
|
|
||||||
return render_nao_elegivel unless motorista_na_consolidacao?(motorista)
|
return render_nao_elegivel unless motorista_na_consolidacao?(motorista)
|
||||||
|
|
||||||
# Recorte por veículo (fechar um carro de cada vez). Sem veículo = todos.
|
# Recorte por veículo(s) selecionado(s). Sem veículo = todos.
|
||||||
elegiveis = tracking_ids_elegiveis(motorista, params[:vehicle].presence)
|
elegiveis = tracking_ids_elegiveis(motorista, params[:vehicle])
|
||||||
# Sem tracking_ids = todas as elegíveis do período/veículo (botão "todos").
|
# Sem tracking_ids = todas as elegíveis do período/veículo (botão "todos").
|
||||||
# Com tracking_ids → mantém só as que de fato são elegíveis para o motorista.
|
# Com tracking_ids → mantém só as que de fato são elegíveis para o motorista.
|
||||||
tracking_ids = tracking_ids.empty? ? elegiveis : (tracking_ids & elegiveis)
|
tracking_ids = tracking_ids.empty? ? elegiveis : (tracking_ids & elegiveis)
|
||||||
@@ -148,10 +148,10 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
qtd: tracking_ids.size, motorista: motorista })
|
qtd: tracking_ids.size, motorista: motorista })
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json { render json: resumo_json(motorista, vehicle: params[:vehicle].presence) }
|
format.json { render json: resumo_json(motorista, vehicles: params[:vehicle]) }
|
||||||
format.html do
|
format.html do
|
||||||
verbo = remover ? 'desmarcadas de' : 'marcadas como'
|
verbo = remover ? 'desmarcadas de' : 'marcadas como'
|
||||||
redirect_to validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: motorista, vehicle: params[:vehicle].presence),
|
redirect_to validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: motorista, vehicle: veiculos_param(params[:vehicle]).presence),
|
||||||
notice: "#{tracking_ids.size} entregas #{verbo} #{tipo.humanize}."
|
notice: "#{tracking_ids.size} entregas #{verbo} #{tipo.humanize}."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -347,9 +347,20 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
rel.pluck(:tracking_id)
|
rel.pluck(:tracking_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Recorte por um único veículo (trata o grupo "sem veículo").
|
# Normaliza o parâmetro de veículo (string única OU array vindo de vehicle[])
|
||||||
def filtrar_por_veiculo(rel, veiculo)
|
# numa lista limpa de selecionados.
|
||||||
veiculo == SEM_VEICULO ? rel.where(vehicle: [nil, '']) : rel.da_veiculo(veiculo)
|
def veiculos_param(raw)
|
||||||
|
Array(raw).reject(&:blank?)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Recorte por um OU MAIS veículos (trata o grupo "sem veículo"). Lista vazia
|
||||||
|
# = sem recorte (todos os veículos).
|
||||||
|
def filtrar_por_veiculo(rel, veiculos)
|
||||||
|
lista = veiculos_param(veiculos)
|
||||||
|
return rel if lista.empty?
|
||||||
|
valores = lista.reject { |v| v == SEM_VEICULO }
|
||||||
|
valores += [nil, ''] if lista.include?(SEM_VEICULO)
|
||||||
|
rel.where(vehicle: valores)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Status "fechado" por veículo do motorista: lista de
|
# Status "fechado" por veículo do motorista: lista de
|
||||||
@@ -447,21 +458,28 @@ class ConsolidacaoEntregasController < ApplicationController
|
|||||||
rel_manual.where.not(tipo: ConsolidacaoEntrega.tipos[:termo]).distinct.count(:tracking_id)
|
rel_manual.where.not(tipo: ConsolidacaoEntrega.tipos[:termo]).distinct.count(:tracking_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
# `vehicle` (opcional): quando presente, `classificadas_escopo` reflete só aquele
|
# `vehicles` (opcional, string ou array): quando presente, TODO o resumo
|
||||||
# carro (para a barra de progresso por veículo). `veiculos_status` acompanha o
|
# (barra de progresso, contagem por pilar e valor total) reflete apenas o(s)
|
||||||
# payload para o front atualizar os chips sem recarregar.
|
# veículo(s) selecionado(s). `veiculos_status` acompanha o payload para o front
|
||||||
def resumo_json(motorista, vehicle: nil)
|
# atualizar os chips sem recarregar.
|
||||||
|
def resumo_json(motorista, vehicles: nil)
|
||||||
|
lista = veiculos_param(vehicles)
|
||||||
classificacoes = @consolidacao.consolidacao_entregas.where(motorista_nome: motorista)
|
classificacoes = @consolidacao.consolidacao_entregas.where(motorista_nome: motorista)
|
||||||
status = veiculos_status(motorista)
|
status = veiculos_status(motorista)
|
||||||
classificadas = classificacoes.distinct.count(:tracking_id)
|
classificadas_motorista = classificacoes.distinct.count(:tracking_id)
|
||||||
escopo = if vehicle.present?
|
|
||||||
(status.find { |v| v[:vehicle] == vehicle } || {})[:classificadas] || 0
|
if lista.any?
|
||||||
else
|
# Recorta as classificações às NFs dos veículos selecionados.
|
||||||
classificadas
|
ids = tracking_ids_elegiveis(motorista, lista)
|
||||||
end
|
classificacoes = classificacoes.where(tracking_id: ids)
|
||||||
|
escopo = status.select { |v| lista.include?(v[:vehicle]) }.sum { |v| v[:classificadas] }
|
||||||
|
else
|
||||||
|
escopo = classificadas_motorista
|
||||||
|
end
|
||||||
|
|
||||||
{
|
{
|
||||||
ok: true,
|
ok: true,
|
||||||
classificadas: classificadas,
|
classificadas: classificadas_motorista,
|
||||||
classificadas_escopo: escopo,
|
classificadas_escopo: escopo,
|
||||||
manuais: contar_manuais(classificacoes.where(manual: true)),
|
manuais: contar_manuais(classificacoes.where(manual: true)),
|
||||||
por_tipo: classificacoes.group(:tipo).sum(:quantidade),
|
por_tipo: classificacoes.group(:tipo).sum(:quantidade),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default class extends Controller {
|
|||||||
massaUrl: String, // POST classificar_em_massa
|
massaUrl: String, // POST classificar_em_massa
|
||||||
motorista: String,
|
motorista: String,
|
||||||
total: Number,
|
total: Number,
|
||||||
veiculo: String, // veículo selecionado (filtro "fechar por carro")
|
veiculos: Array, // veículo(s) selecionado(s) — filtro multi-seleção
|
||||||
precoExtraordinaria: Number // preço padrão sugerido no prompt
|
precoExtraordinaria: Number // preço padrão sugerido no prompt
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ export default class extends Controller {
|
|||||||
tracking_id: tracking,
|
tracking_id: tracking,
|
||||||
tipo: tipo,
|
tipo: tipo,
|
||||||
motorista: this.motoristaValue,
|
motorista: this.motoristaValue,
|
||||||
vehicle: this.veiculoValue,
|
vehicle: this.veiculosValue,
|
||||||
valor: valor
|
valor: valor
|
||||||
})
|
})
|
||||||
// resp.ativo indica se o pilar ficou ligado ou desligado (toggle)
|
// resp.ativo indica se o pilar ficou ligado ou desligado (toggle)
|
||||||
@@ -101,7 +101,7 @@ export default class extends Controller {
|
|||||||
const resp = await this.post(this.massaUrlValue, {
|
const resp = await this.post(this.massaUrlValue, {
|
||||||
tipo: tipo,
|
tipo: tipo,
|
||||||
motorista: this.motoristaValue,
|
motorista: this.motoristaValue,
|
||||||
vehicle: this.veiculoValue,
|
vehicle: this.veiculosValue,
|
||||||
tracking_ids: ids,
|
tracking_ids: ids,
|
||||||
acao: remover ? "remover" : "adicionar",
|
acao: remover ? "remover" : "adicionar",
|
||||||
valor: valor
|
valor: valor
|
||||||
@@ -212,12 +212,13 @@ export default class extends Controller {
|
|||||||
if (total) total.textContent = dados.eligible
|
if (total) total.textContent = dados.eligible
|
||||||
if (check) check.textContent = dados.fechado ? "✓" : ""
|
if (check) check.textContent = dados.fechado ? "✓" : ""
|
||||||
|
|
||||||
// Estado de cor determinístico: verde (fechado) > laranja (selecionado) > neutro.
|
// Estado de cor determinístico: laranja (selecionado) > verde (fechado) > neutro.
|
||||||
|
// Seleção tem prioridade para o usuário sempre enxergar quais carros somam.
|
||||||
chip.classList.remove(...VERDE, ...LARANJA, ...NEUTRO)
|
chip.classList.remove(...VERDE, ...LARANJA, ...NEUTRO)
|
||||||
if (dados.fechado) {
|
if (this.veiculosValue.includes(chip.dataset.vehicle)) {
|
||||||
chip.classList.add(...VERDE)
|
|
||||||
} else if (chip.dataset.vehicle === this.veiculoValue) {
|
|
||||||
chip.classList.add(...LARANJA)
|
chip.classList.add(...LARANJA)
|
||||||
|
} else if (dados.fechado) {
|
||||||
|
chip.classList.add(...VERDE)
|
||||||
} else {
|
} else {
|
||||||
chip.classList.add(...NEUTRO)
|
chip.classList.add(...NEUTRO)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
data-validacao-massa-url-value="<%= classificar_em_massa_consolidacao_consolidacao_entregas_path(@consolidacao) %>"
|
data-validacao-massa-url-value="<%= classificar_em_massa_consolidacao_consolidacao_entregas_path(@consolidacao) %>"
|
||||||
data-validacao-motorista-value="<%= @motorista %>"
|
data-validacao-motorista-value="<%= @motorista %>"
|
||||||
data-validacao-total-value="<%= @total_entregas %>"
|
data-validacao-total-value="<%= @total_entregas %>"
|
||||||
data-validacao-veiculo-value="<%= @veiculo %>"
|
data-validacao-veiculos-value="<%= @veiculos_sel.to_json %>"
|
||||||
data-validacao-preco-extraordinaria-value="<%= @precos[:extraordinaria] %>">
|
data-validacao-preco-extraordinaria-value="<%= @precos[:extraordinaria] %>">
|
||||||
|
|
||||||
<%# Cabeçalho + controles fixos no topo (no desktop); só a lista de NFs rola. %>
|
<%# Cabeçalho + controles fixos no topo (no desktop); só a lista de NFs rola. %>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl p-4 mb-4">
|
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl p-4 mb-4">
|
||||||
<div class="flex justify-between text-sm mb-2">
|
<div class="flex justify-between text-sm mb-2">
|
||||||
<span class="text-white font-semibold">
|
<span class="text-white font-semibold">
|
||||||
<% if @veiculo.present? %>🚚 <%= @veiculo %> — <% end %>
|
<% if @veiculos_sel.any? %>🚚 <%= @veiculos_sel.join(', ') %> — <% end %>
|
||||||
<span data-validacao-target="contadorClassificadas"><%= @classificadas %></span>
|
<span data-validacao-target="contadorClassificadas"><%= @classificadas %></span>
|
||||||
de <span data-validacao-target="contadorTotal"><%= @total_entregas %></span> entregas classificadas
|
de <span data-validacao-target="contadorTotal"><%= @total_entregas %></span> entregas classificadas
|
||||||
<span data-validacao-target="manuaisInfo" class="<%= 'hidden' unless @manuais.positive? %> text-blue-400 font-normal">·
|
<span data-validacao-target="manuaisInfo" class="<%= 'hidden' unless @manuais.positive? %> text-blue-400 font-normal">·
|
||||||
@@ -52,22 +52,24 @@
|
|||||||
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl p-4 mb-4">
|
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl p-4 mb-4">
|
||||||
<div class="flex items-center gap-2 mb-2">
|
<div class="flex items-center gap-2 mb-2">
|
||||||
<span class="text-gray-400 text-sm font-semibold">🚗 Fechar por veículo:</span>
|
<span class="text-gray-400 text-sm font-semibold">🚗 Fechar por veículo:</span>
|
||||||
<span class="text-gray-600 text-xs">clique para filtrar e classificar um carro de cada vez</span>
|
<span class="text-gray-600 text-xs">clique para filtrar/somar um ou vários carros (clique de novo p/ tirar)</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
<%# Chip "Todos" %>
|
<%# Chip "Todos" — limpa a seleção (mostra todos os carros) %>
|
||||||
<%= link_to validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista),
|
<%= link_to validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista),
|
||||||
class: "px-3 py-2 rounded-lg text-sm font-semibold border min-h-[40px] flex items-center
|
class: "px-3 py-2 rounded-lg text-sm font-semibold border min-h-[40px] flex items-center
|
||||||
#{@veiculo.blank? ? 'border-orange-500 text-orange-400 bg-orange-500/10' : 'border-[#2a2a2a] text-gray-300 hover:border-orange-500'}" do %>
|
#{@veiculos_sel.empty? ? 'border-orange-500 text-orange-400 bg-orange-500/10' : 'border-[#2a2a2a] text-gray-300 hover:border-orange-500'}" do %>
|
||||||
Todos
|
Todos
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% @veiculos_status.each do |v| %>
|
<% @veiculos_status.each do |v| %>
|
||||||
<% selecionado = (@veiculo == v[:vehicle]) %>
|
<% selecionado = @veiculos_sel.include?(v[:vehicle]) %>
|
||||||
<%= link_to validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista, vehicle: v[:vehicle]),
|
<%# Alterna este veículo dentro da seleção atual (multi-seleção) %>
|
||||||
|
<% nova_sel = selecionado ? (@veiculos_sel - [v[:vehicle]]) : (@veiculos_sel + [v[:vehicle]]) %>
|
||||||
|
<%= link_to validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista, vehicle: nova_sel.presence),
|
||||||
data: { 'validacao-target': 'chipVeiculo', vehicle: v[:vehicle], eligible: v[:eligible] },
|
data: { 'validacao-target': 'chipVeiculo', vehicle: v[:vehicle], eligible: v[:eligible] },
|
||||||
class: "px-3 py-2 rounded-lg text-sm font-semibold border min-h-[40px] flex items-center gap-2 transition-colors
|
class: "px-3 py-2 rounded-lg text-sm font-semibold border min-h-[40px] flex items-center gap-2 transition-colors
|
||||||
#{v[:fechado] ? 'border-green-500 text-green-400 bg-green-500/10' : (selecionado ? 'border-orange-500 text-orange-400 bg-orange-500/10' : 'border-[#2a2a2a] text-gray-300 hover:border-orange-500')}" do %>
|
#{selecionado ? 'border-orange-500 text-orange-400 bg-orange-500/10' : (v[:fechado] ? 'border-green-500 text-green-400 bg-green-500/10' : 'border-[#2a2a2a] text-gray-300 hover:border-orange-500')}" do %>
|
||||||
<span><%= v[:vehicle] %></span>
|
<span><%= v[:vehicle] %></span>
|
||||||
<span class="text-xs <%= v[:fechado] ? 'text-green-400' : 'text-gray-500' %>">
|
<span class="text-xs <%= v[:fechado] ? 'text-green-400' : 'text-gray-500' %>">
|
||||||
<span data-chip-feito><%= v[:classificadas] %></span>/<span data-chip-total><%= v[:eligible] %></span>
|
<span data-chip-feito><%= v[:classificadas] %></span>/<span data-chip-total><%= v[:eligible] %></span>
|
||||||
@@ -104,7 +106,7 @@
|
|||||||
|
|
||||||
<div class="ml-auto">
|
<div class="ml-auto">
|
||||||
<%= link_to params[:apenas_pendentes] == '1' ? 'Mostrar todas' : 'Apenas não classificadas',
|
<%= link_to params[:apenas_pendentes] == '1' ? 'Mostrar todas' : 'Apenas não classificadas',
|
||||||
validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista, vehicle: @veiculo,
|
validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista, vehicle: @veiculos_sel.presence,
|
||||||
apenas_pendentes: params[:apenas_pendentes] == '1' ? nil : '1'),
|
apenas_pendentes: params[:apenas_pendentes] == '1' ? nil : '1'),
|
||||||
class: 'text-orange-400 hover:text-orange-300 text-sm border border-orange-500/40 px-3 py-2 rounded-lg' %>
|
class: 'text-orange-400 hover:text-orange-300 text-sm border border-orange-500/40 px-3 py-2 rounded-lg' %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||