Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
81 changes: 81 additions & 0 deletions app/pdfs/event_procedures_report_pdf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# 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
@header_footer_height = 100
@line_spacing = 15
@text_box_padding = 10
@right_text_offset = 110
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 @line_spacing

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

def start_new_page_if_needed
return unless pdf.cursor < @header_footer_height

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 - @text_box_padding], size: 10, align: :left
pdf.text_box right_text, at: [pdf.bounds.width - @right_text_offset, pdf.cursor - @text_box_padding], size: 10,
align: :right
end
pdf.move_down @line_spacing
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
37 changes: 37 additions & 0 deletions app/pdfs/footer_pdf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

class FooterPdf
attr_reader :pdf, :amount

def initialize(pdf:, amount:)
@pdf = pdf
@amount = amount
@footer_height = 50
@footer_spacing = 15
@footer_font_size = 10
@right_text_offset = 50
end

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

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

pdf.move_down @footer_spacing

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

pdf.move_down @footer_spacing

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

class HeaderPdf
attr_reader :pdf, :title

def initialize(pdf:, title:)
@pdf = pdf
@title = title
@header_spacing = 20
@header_font_size = 12
@title_font_size = 20
end

def generate
pdf.text "Data: #{Time.zone.now.strftime('%d/%m/%Y')}", align: :right, size: @header_font_size
pdf.move_down @header_spacing
pdf.text title, align: :center, size: @title_font_size, style: :bold
pdf.move_down @header_spacing
end
end
93 changes: 93 additions & 0 deletions app/pdfs/medical_shifts_report_pdf.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# 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
@header_footer_height = 100
@line_spacing = 15
@text_box_padding = 10
@right_text_offset = 110
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 @line_spacing

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

def start_new_page_if_needed
return unless pdf.cursor < @header_footer_height

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 - @text_box_padding], size: 10, align: :left
pdf.text_box right_text, at: [pdf.bounds.width - @right_text_offset, pdf.cursor - @text_box_padding], size: 10,
align: :right
end
pdf.move_down @line_spacing
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
Loading
Loading