Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ gem "omniauth-strava"
gem "packwerk", "3.1.0"
# Track changes to your models, for auditing or versioning.
gem "paper_trail", "15.1.0"
# This library provides a number of PDF::Reader based tools for use in testing PDF output.
gem "pdf-inspector", "1.3.0"
# Use pg as the database for Active Record
gem "pg", "1.5.4"
# Prawn is a pure Ruby PDF generation library [https://github.com/cortiz/prawn-rails]
Expand Down
13 changes: 13 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ GIT
GEM
remote: https://rubygems.org/
specs:
Ascii85 (2.0.1)
actioncable (7.1.3.4)
actionpack (= 7.1.3.4)
activesupport (= 7.1.3.4)
Expand Down Expand Up @@ -106,6 +107,7 @@ GEM
kaminari (~> 1.2.2)
sassc-rails (~> 2.1)
selectize-rails (~> 0.6)
afm (0.2.2)
ast (2.4.2)
base64 (0.1.1)
bcrypt (3.1.20)
Expand Down Expand Up @@ -204,6 +206,7 @@ GEM
ffi (1.17.0-x86_64-linux-gnu)
globalid (1.2.1)
activesupport (>= 6.1)
hashery (2.1.2)
hashie (5.0.0)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -321,6 +324,14 @@ GEM
ast (~> 2.4.1)
racc
pdf-core (0.10.0)
pdf-inspector (1.3.0)
pdf-reader (>= 1.0, < 3.0.a)
pdf-reader (2.13.0)
Ascii85 (>= 1.0, < 3.0, != 2.0.0)
afm (~> 0.2.1)
hashery (~> 2.0)
ruby-rc4
ttfunk
pg (1.5.4)
prawn (2.5.0)
matrix (~> 0.4)
Expand Down Expand Up @@ -463,6 +474,7 @@ GEM
rubocop-rspec_rails (2.28.3)
rubocop (~> 1.40)
ruby-progressbar (1.13.0)
ruby-rc4 (0.1.5)
rubyzip (2.3.2)
sassc (2.4.0)
ffi (~> 1.9)
Expand Down Expand Up @@ -576,6 +588,7 @@ DEPENDENCIES
omniauth-strava
packwerk (= 3.1.0)
paper_trail (= 15.1.0)
pdf-inspector (= 1.3.0)
pg (= 1.5.4)
prawn-rails (= 1.6.0)
pry (= 0.14.2)
Expand Down
78 changes: 72 additions & 6 deletions app/controllers/api/v1/pdf_reports_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,81 @@ module V1
class PdfReportsController < ApiController
def generate
authorize :pdf_report, :generate?
pdf = Prawn::Document.new do
text "Mock PDF para Testes"
move_down 10
text "Data de Geração: #{Time.zone.now.strftime('%d/%m/%Y %H:%M:%S')}"
return entity_name_failure_response if params[:entity_name].blank?

pdf = if permitted_query_params[:entity_name] == "event_procedures"
event_procedures_pdf
else
medical_shifts_pdf
end

disposition = params[:disposition] || "inline"
send_data pdf.render, filename: filename, type: "application/pdf", disposition: disposition
end

private

def disposition
permitted_query_params[:disposition] || "inline"
end

def filename
"#{Time.zone.now.strftime('%d%m%Y')}_report.pdf"
end

def entity_name_failure_response
render json: { error: "You must inform the `entity_name` parameter" }, status: :bad_request
end

def event_procedures_pdf
authorized_scope = policy_scope(EventProcedure)
event_procedures = EventProcedures::List.result(
scope: authorized_scope,
params: permitted_query_params
).event_procedures
total_amount_cents = EventProcedures::TotalAmountCents.call(total_amount_cents_params)

PdfGeneratorService.new(
relation: event_procedures,
amount: total_amount_cents,
entity_name: permitted_query_params[:entity_name]
).generate_pdf
end

def medical_shifts_pdf
authorized_scope = policy_scope(MedicalShift)
medical_shifts = MedicalShifts::List.result(
scope: authorized_scope,
params: permitted_query_params
).medical_shifts
total_amount_cents = MedicalShifts::TotalAmountCents.call(user_id: current_user.id, month: params[:month])

PdfGeneratorService.new(
relation: medical_shifts,
amount: total_amount_cents,
entity_name: permitted_query_params[:entity_name]
).generate_pdf
end

def permitted_query_params
params.permit(
:page,
:per_page,
:month,
:year,
:payd,
:entity_name,
:disposition,
hospital: [:name],
health_insurance: [:name]
).to_h
end

send_data pdf.render, filename: "mock_report.pdf", type: "application/pdf", disposition: disposition
def total_amount_cents_params
{
user_id: current_user.id,
month: permitted_query_params[:month],
year: permitted_query_params[:year]
}
end
end
end
Expand Down
76 changes: 76 additions & 0 deletions app/pdfs/event_procedures_report_pdf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true

class EventProceduresReportPdf
attr_reader :pdf, :items, :amount, :title

def initialize(pdf:, items:, amount:, title:)
@pdf = pdf
@items = items
@amount = amount
@title = title
end

def generate
add_header
add_body
add_footer
end

private

def add_header
pdf.repeat(:all) do
HeaderPdf.new(pdf: pdf, title: title).generate
end
end

def add_footer
pdf.repeat(:all, dynamic: true) do
FooterPdf.new(pdf: pdf, amount: amount).generate
end
end

def add_body
pdf.move_down 10

items.each do |item|
start_new_page_if_needed
pdf.stroke_horizontal_rule
add_item_details(item)
pdf.move_down 10
end
end

def start_new_page_if_needed
return unless pdf.cursor < 100

pdf.start_new_page
add_header
end

def add_item_details(item)
add_item_line(truncate_text(item.patient.name), item_paid?(item))
add_item_line(truncate_text(item.procedure.name), item.procedure.amount.format)
add_item_line(truncate_text(item.health_insurance.name), item_date(item))
end

def add_item_line(left_text, right_text)
pdf.bounding_box([0, pdf.cursor], width: pdf.bounds.width) do
pdf.text_box left_text, at: [3, pdf.cursor - 10], size: 10, align: :left
pdf.text_box right_text, at: [pdf.bounds.width - 110, pdf.cursor - 10], size: 10, align: :right
end
pdf.move_down 15
end

def truncate_text(text, length = 35)
text.length > length ? "#..." : text
end

def item_paid?(item)
item.payd ? "Pago" : "A Receber"
end

def item_date(item)
item.date.strftime("%d/%m/%Y")
end
end
30 changes: 30 additions & 0 deletions app/pdfs/footer_pdf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

class FooterPdf
attr_reader :pdf, :amount

def initialize(pdf:, amount:)
@pdf = pdf
@amount = amount
end

def generate
pdf.bounding_box([0, 30], width: @pdf.bounds.width, height: 50) do
pdf.stroke_color "000000"
pdf.stroke_horizontal_line(0, pdf.bounds.width, at: 65)

pdf.text_box "Total", at: [0, pdf.cursor], size: 10, align: :left
pdf.text_box amount.total, at: [pdf.bounds.width - 50, pdf.cursor], size: 10, align: :right

pdf.move_down 15

pdf.text_box "A Receber", at: [0, pdf.cursor], size: 10, align: :left
pdf.text_box amount.unpaid, at: [pdf.bounds.width - 50, pdf.cursor], size: 10, align: :right

pdf.move_down 15

pdf.text_box "Recebidos", at: [0, pdf.cursor], size: 10, align: :left
pdf.text_box amount.payd, at: [pdf.bounds.width - 50, pdf.cursor], size: 10, align: :right
end
end
end
17 changes: 17 additions & 0 deletions app/pdfs/header_pdf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

class HeaderPdf
attr_reader :pdf, :title

def initialize(pdf:, title:)
@pdf = pdf
@title = title
end

def generate
pdf.text "Data: #{Time.zone.now.strftime('%d/%m/%Y')}", align: :right, size: 12
pdf.move_down 20
pdf.text title, align: :center, size: 20, style: :bold
pdf.move_down 20
end
end
88 changes: 88 additions & 0 deletions app/pdfs/medical_shifts_report_pdf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# frozen_string_literal: true

class MedicalShiftsReportPdf
attr_reader :pdf, :items, :amount, :title

def initialize(pdf:, items:, amount:, title:)
@pdf = pdf
@items = items
@amount = amount
@title = title
end

def generate
add_header
add_body
add_footer
end

private

def add_header
pdf.repeat(:all) do
HeaderPdf.new(pdf: pdf, title: title).generate
end
end

def add_footer
pdf.repeat(:all, dynamic: true) do
FooterPdf.new(pdf: pdf, amount: amount).generate
end
end

def add_body
pdf.move_down 10

items.each do |item|
start_new_page_if_needed
pdf.stroke_horizontal_rule
add_item_details(item)
pdf.move_down 10
end
end

def start_new_page_if_needed
return unless pdf.cursor < 100

pdf.start_new_page
add_header
end

def add_item_details(item)
add_item_line(truncate_text(item.hospital_name), item_start_date(item))
add_item_line(item_workload(item), item.amount.format)
add_item_line(item_start_hour(item), item_paid?(item))
end

def add_item_line(left_text, right_text)
pdf.bounding_box([0, pdf.cursor], width: pdf.bounds.width) do
pdf.text_box left_text, at: [3, pdf.cursor - 10], size: 10, align: :left
pdf.text_box right_text, at: [pdf.bounds.width - 110, pdf.cursor - 10], size: 10, align: :right
end
pdf.move_down 15
end

def truncate_text(text, length = 35)
text.length > length ? "#..." : text
end

def item_shift(item)
item.shift == "Daytime" ? "Diurno" : "Noturno"
end

def item_workload(item)
"#{item_shift(item)} - #{item.workload_humanize}"
end

def item_start_date(item)
item.start_date.strftime("%d/%m/%Y")
end

def item_start_hour(item)
"Início: #{item.start_hour.strftime('%H:%M')}"
end

def item_paid?(item)
item.payd ? "Pago" : "A Receber"
end
end
29 changes: 29 additions & 0 deletions app/services/pdf_generator_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

class PdfGeneratorService
attr_reader :relation, :amount, :entity_name

def initialize(relation:, amount:, entity_name:)
@relation = relation
@amount = amount
@entity_name = entity_name
end

def generate_pdf
entity_name == "event_procedures" ? generate_event_procedures_pdf : generate_medical_shifts_pdf
end

private

def generate_event_procedures_pdf
Prawn::Document.new do |pdf|
EventProceduresReportPdf.new(pdf: pdf, items: relation, amount: amount, title: "Procedimentos").generate
end
end

def generate_medical_shifts_pdf
Prawn::Document.new do |pdf|
MedicalShiftsReportPdf.new(pdf: pdf, items: relation, amount: amount, title: "Plantões").generate
end
end
end
Loading
Loading