Skip to content

Commit a640773

Browse files
committed
add a new report to confirmed productions
1 parent 7c5c761 commit a640773

File tree

6 files changed

+248
-1
lines changed

6 files changed

+248
-1
lines changed

app/controllers/productions_controller.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,28 @@ def payment_order_pdf
129129
send_data pdf.render, filename: "payment_order_#{@production.service_order_number}.pdf", type: 'application/pdf', disposition: 'inline'
130130
end
131131

132+
def unpaid_confirmed
133+
@unpaid_confirmed_productions = Production.includes(:tailor, production_products: :product)
134+
.where(confirmed: true, paid: false)
135+
.order(cut_date: :desc, service_order_number: :desc)
136+
137+
@paid_productions = Production.includes(:tailor, production_products: :product)
138+
.where(confirmed: true, paid: true)
139+
.order(payment_date: :desc, service_order_number: :desc)
140+
141+
if params[:tailor_id].present?
142+
@unpaid_confirmed_productions = @unpaid_confirmed_productions.where(tailor_id: params[:tailor_id])
143+
@paid_productions = @paid_productions.where(tailor_id: params[:tailor_id])
144+
end
145+
146+
@tailors_summary = calculate_tailors_summary_unpaid(@unpaid_confirmed_productions)
147+
148+
respond_to do |format|
149+
format.html
150+
format.csv { send_data generate_unpaid_confirmed_csv, filename: "unpaid_confirmed_productions_#{Date.today}.csv" }
151+
end
152+
end
153+
132154
private
133155

134156
def set_production
@@ -172,6 +194,27 @@ def calculate_tailors_summary(productions)
172194
summary
173195
end
174196

197+
def calculate_tailors_summary_unpaid(productions)
198+
summary = productions.each_with_object({}) do |production, summary|
199+
tailor_id = production.tailor_id
200+
summary[tailor_id] ||= { productions_count: 0, total_value: 0, products: {} }
201+
summary[tailor_id][:productions_count] += 1
202+
203+
production.production_products.each do |pp|
204+
summary[tailor_id][:total_value] += pp.total_price if pp.total_price
205+
summary[tailor_id][:products][pp.product_id] ||= { count: 0, value: 0 }
206+
summary[tailor_id][:products][pp.product_id][:count] += pp.quantity
207+
summary[tailor_id][:products][pp.product_id][:value] += pp.total_price if pp.total_price
208+
end
209+
end
210+
211+
summary.each do |tailor_id, tailor_summary|
212+
tailor_summary[:products] = tailor_summary[:products].sort_by { |_, data| -data[:value] }.to_h
213+
end
214+
215+
summary
216+
end
217+
175218
def generate_tailors_summary_csv
176219
require 'csv'
177220

@@ -207,4 +250,24 @@ def generate_products_in_production_csv
207250
end
208251
end
209252
end
253+
254+
def generate_unpaid_confirmed_csv
255+
require 'csv'
256+
257+
CSV.generate(headers: true) do |csv|
258+
csv << ['Tailor Name', 'Total Productions', 'Total Value', 'Products']
259+
260+
@tailors_summary.each do |tailor_id, summary|
261+
tailor = Tailor.find(tailor_id)
262+
products_summary = summary[:products].map { |product_id, data| "#{Product.find(product_id).name}: #{data[:count]} (#{number_to_currency(data[:value])})" }.join(', ')
263+
264+
csv << [
265+
tailor.name,
266+
summary[:productions_count],
267+
number_to_currency(summary[:total_value]),
268+
products_summary
269+
]
270+
end
271+
end
272+
end
210273
end
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<div class="row mt-3">
2+
<% productions.each do |production| %>
3+
<div class="col-12 mb-4">
4+
<div class="card">
5+
<div class="card-header">
6+
<h5 class="card-title"><%= t('.service_order_number') %>: <%= production.service_order_number %></h5>
7+
</div>
8+
<div class="card-body">
9+
<div class="row mb-3">
10+
<div class="col-md-4">
11+
<p><strong><%= Production.human_attribute_name(:tailor) %>:</strong> <%= production.tailor.name %></p>
12+
<p><strong><%= Production.human_attribute_name(:cut_date) %>:</strong> <%= l(production.cut_date, format: :long) if production.cut_date %></p>
13+
<p><strong><%= Production.human_attribute_name(:expected_delivery_date) %>:</strong> <%= l(production.expected_delivery_date, format: :long) if production.expected_delivery_date %></p>
14+
<p><strong><%= Production.human_attribute_name(:payment_date) %>:</strong> <%= l(production.payment_date, format: :long) if production.payment_date %></p>
15+
</div>
16+
</div>
17+
<h6 class="mt-4"><%= t('.products') %>:</h6>
18+
<div class="table-responsive">
19+
<table class="table table-sm">
20+
<thead>
21+
<tr>
22+
<th><%= t('.product') %></th>
23+
<th><%= t('.quantity') %></th>
24+
<th><%= t('.pieces_delivered') %></th>
25+
<th><%= t('.unit_price') %></th>
26+
<th><%= t('.dirty') %></th>
27+
<th><%= t('.error') %></th>
28+
<th><%= t('.discard') %></th>
29+
<th><%= t('.returned') %></th>
30+
<th><%= t('.discount') %></th>
31+
<th><%= t('.total') %></th>
32+
</tr>
33+
</thead>
34+
<tbody>
35+
<% total_all_rows = 0 %>
36+
<% total_discount = 0 %>
37+
<% production.production_products.each do |pp| %>
38+
<% unit_price = pp.unit_price || 0 %>
39+
<% total_price = pp.total_price || 0 %>
40+
<% adjusted_quantity = pp.pieces_delivered - (pp.dirty + pp.error + pp.discard) %>
41+
<% discount = unit_price * (pp.dirty + pp.error + pp.discard) %>
42+
<% returned_discount = pp.returned ? total_price : 0 %>
43+
<% total_discount_row = discount + returned_discount %>
44+
<% adjusted_price = unit_price * adjusted_quantity - total_discount_row %>
45+
46+
<% total_all_rows += total_price %>
47+
<% total_discount += total_discount_row %>
48+
49+
<tr>
50+
<td><%= pp.product.name %></td>
51+
<td><%= pp.quantity %></td>
52+
<td><%= pp.pieces_delivered %></td>
53+
<td><%= number_to_currency(unit_price) %></td>
54+
<td><%= pp.dirty %></td>
55+
<td><%= pp.error %></td>
56+
<td><%= pp.discard %></td>
57+
<td><%= pp.returned ? t('yes') : t('no') %></td>
58+
<td><%= number_to_currency(total_discount_row) %></td>
59+
<td><%= number_to_currency(adjusted_price) %></td>
60+
</tr>
61+
<% end %>
62+
</tbody>
63+
<tfoot>
64+
<tr>
65+
<th colspan="9" class="text-right"><%= t('.total_discount') %>:</th>
66+
<th><%= number_to_currency(total_discount) %></th>
67+
</tr>
68+
<tr>
69+
<th colspan="9" class="text-right"><%= t('.total_to_pay') %>:</th>
70+
<th><%= number_to_currency(total_all_rows - total_discount) %></th>
71+
</tr>
72+
</tfoot>
73+
</table>
74+
</div>
75+
</div>
76+
</div>
77+
</div>
78+
<% end %>
79+
</div>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<br><br>
2+
<div class="container-fluid">
3+
<h1 class="mb-4"><%= t('productions.unpaid_confirmed.title') %></h1>
4+
5+
<%= form_tag unpaid_confirmed_productions_path, method: :get, class: 'mb-4' do %>
6+
<div class="form-group">
7+
<%= label_tag :tailor_id, t('.filter_by_tailor') %>
8+
<%= select_tag :tailor_id,
9+
options_from_collection_for_select(Tailor.all, :id, :name, params[:tailor_id]),
10+
include_blank: t('.all_tailors'),
11+
class: 'form-control' %>
12+
</div>
13+
<%= submit_tag t('productions.unpaid_confirmed.apply_filter'), class: 'btn btn-primary' %>
14+
<% end %>
15+
16+
<%= link_to t('.download_csv'), unpaid_confirmed_productions_path(format: :csv, tailor_id: params[:tailor_id]), class: 'btn btn-secondary mb-3' %>
17+
18+
<ul class="nav nav-tabs" id="myTab" role="tablist">
19+
<li class="nav-item" role="presentation">
20+
<a class="nav-link active" id="unpaid-tab" data-toggle="tab" href="#unpaid" role="tab" aria-controls="unpaid" aria-selected="true">Unpaid Productions</a>
21+
</li>
22+
<li class="nav-item" role="presentation">
23+
<a class="nav-link" id="paid-tab" data-toggle="tab" href="#paid" role="tab" aria-controls="paid" aria-selected="false">Paid Productions</a>
24+
</li>
25+
<li class="nav-item" role="presentation">
26+
<a class="nav-link" id="tailors-tab" data-toggle="tab" href="#tailors" role="tab" aria-controls="tailors" aria-selected="false">Tailors Summary</a>
27+
</li>
28+
</ul>
29+
30+
<div class="tab-content" id="myTabContent">
31+
<div class="tab-pane fade show active" id="unpaid" role="tabpanel" aria-labelledby="unpaid-tab">
32+
<%= render 'production_list', productions: @unpaid_confirmed_productions %>
33+
</div>
34+
35+
<div class="tab-pane fade" id="paid" role="tabpanel" aria-labelledby="paid-tab">
36+
<%= render 'production_list', productions: @paid_productions %>
37+
</div>
38+
39+
<div class="tab-pane fade" id="tailors" role="tabpanel" aria-labelledby="tailors-tab">
40+
<div class="row mt-3">
41+
<% @tailors_summary.each do |tailor_id, summary| %>
42+
<div class="col-md-4 mb-4">
43+
<div class="card">
44+
<div class="card-header">
45+
<h5 class="card-title"><%= Tailor.find(tailor_id).name %></h5>
46+
</div>
47+
<div class="card-body">
48+
<p><strong><%= t('.total_productions') %>:</strong> <%= summary[:productions_count] %></p>
49+
<p><strong><%= t('.total_value') %>:</strong> <%= number_to_currency(summary[:total_value]) %></p>
50+
<h6 class="mt-3"><%= t('.products') %>:</h6>
51+
<ul>
52+
<% summary[:products].each do |product_id, data| %>
53+
<li><%= Product.find(product_id).name %>: <%= data[:count] %> (<%= number_to_currency(data[:value]) %>)</li>
54+
<% end %>
55+
</ul>
56+
</div>
57+
</div>
58+
</div>
59+
<% end %>
60+
</div>
61+
</div>
62+
</div>
63+
</div>
64+
65+
<%= javascript_include_tag 'https://code.jquery.com/jquery-3.5.1.slim.min.js' %>
66+
<%= javascript_include_tag 'https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js' %>
67+
68+
<script>
69+
$(document).ready(function() {
70+
$('#myTab a').on('click', function (e) {
71+
e.preventDefault()
72+
$(this).tab('show')
73+
})
74+
});
75+
</script>

app/views/shared/_sidebar.html.erb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
<li class="<%= active_nav_item('productions', 'missing_pieces') %>">
3535
<%= link_to t("productions.side_missing_pieces"), missing_pieces_productions_path, class: 'nav-link' %>
3636
</li>
37+
<li class="<%= active_nav_item('productions', 'unpaid_confirmed') %>">
38+
<%= link_to t("productions.unpaid_confirmed.title"), unpaid_confirmed_productions_path, class: 'nav-link' %>
39+
</li>
3740
<li class="<%= active_nav_item('productions', 'products_in_production_report') %>">
3841
<%= link_to t("productions.products_in_production_report"), products_in_production_report_productions_path, class: 'nav-link' %>
3942
</li>

config/locales/pt-BR.models.productions.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,29 @@ pt-BR:
117117
edit: "Editar %{model}"
118118
actions:
119119
remove: "Remover"
120+
productions:
121+
unpaid_confirmed:
122+
title: "Cortes Concluídos"
123+
filter_by_tailor: "Filtrar por Costureiro"
124+
all_tailors: "Todos os Costureiros"
125+
apply_filter: "Aplicar Filtro"
126+
download_csv: "Baixar CSV"
127+
total_productions: "Total de Produções"
128+
total_value: "Valor Total"
129+
products: "Produtos"
130+
production_list:
131+
service_order_number: "Número da Ordem de Serviço"
132+
product: "Produto"
133+
quantity: "Quantidade"
134+
pieces_delivered: "Peças Entregues"
135+
unit_price: "Preço Un."
136+
dirty: "Sujo"
137+
error: "Erro"
138+
discard: "Descarte"
139+
returned: "Devolvido"
140+
discount: "Desconto"
141+
total: "Total"
142+
total_discount: "Total de Desconto"
143+
total_to_pay: "Total a Pagar"
144+
yes: "Sim"
145+
no: "Não"

config/routes.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
resources :productions do
88
collection do
99
get 'missing_pieces'
10-
get :products_in_production_report
10+
get 'products_in_production_report'
11+
get 'unpaid_confirmed' # Add this line
1112
end
1213
member do
1314
patch :verify

0 commit comments

Comments
 (0)