Skip to content

Commit

Permalink
Add whtmltopdf and pdfkit gem (#7)
Browse files Browse the repository at this point in the history
Co-authored-by: lorenzo farnararo <[email protected]>
  • Loading branch information
Pimentoso and baldarn authored Sep 9, 2024
1 parent c11fab1 commit a718e90
Show file tree
Hide file tree
Showing 43 changed files with 434 additions and 50 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ APP_VERSION=dev
KAMAL_REGISTRY_PASSWORD=redacted
RAILS_MASTER_KEY=redacted
POSTGRES_PASSWORD=redacted

# pdf generation binary
WKHTMLTOPDF_PATH=/usr/local/bin/wkhtmltopdf
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@

/app/assets/builds/*
!/app/assets/builds/.keep

.DS_Store
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Metrics/BlockLength:
Exclude:
- config/environments/*
- config/initializers/simple_form_bootstrap.rb
- config/routes.rb

Layout/LineLength:
Exclude:
Expand Down
5 changes: 3 additions & 2 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2024-08-28 11:51:10 UTC using RuboCop version 1.65.1.
# on 2024-09-04 12:44:30 UTC using RuboCop version 1.65.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand All @@ -23,11 +23,12 @@ Rails/LexicallyScopedActionFilter:
Exclude:
- 'app/controllers/users/registrations_controller.rb'

# Offense count: 1
# Offense count: 2
# Configuration parameters: ForbiddenMethods, AllowedMethods.
# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all
Rails/SkipsModelValidations:
Exclude:
- 'app/models/payment.rb'
- 'db/migrate/20240812090546_add_service_name_to_active_storage_blobs.active_storage.rb'

# Offense count: 1
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl=7* libjemalloc2=5* libpq-dev=15* libvips42=8* nodejs=18* && \
apt-get install --no-install-recommends -y curl=7* libjemalloc2=5* libpq-dev=15* libvips42=8* wkhtmltopdf=0* nodejs=18* && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Copy built artifacts: gems, application
Expand Down
6 changes: 5 additions & 1 deletion Dockerfile.development
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 libpq-dev libvips nodejs && \
apt-get install --no-install-recommends -y curl libjemalloc2 libpq-dev libvips wkhtmltopdf nodejs && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Copy built artifacts: gems, application
Expand All @@ -43,3 +43,7 @@ COPY --from=build /rails /rails

# Entrypoint prepares the application.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["bin/rails", "s", "-b", "0.0.0.0"]
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ gem 'kaminari-i18n'
gem 'devise', '~> 4.9'
gem 'devise-i18n'

# Pdf
gem 'pdfkit'

# Other
gem 'active_storage_validations'
gem 'aws-sdk-s3'
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ GEM
parser (3.3.3.0)
ast (~> 2.4.1)
racc
pdfkit (0.8.7.3)
pg (1.5.7)
popper_js (2.11.8)
prometheus-client (4.2.3)
Expand Down Expand Up @@ -520,6 +521,7 @@ DEPENDENCIES
kaminari-i18n
logtail-rails (~> 0.2.7)
mission_control-jobs (~> 0.3.1)
pdfkit
pg (~> 1.5.7)
puma (>= 5.0)
rack-attack
Expand Down
3 changes: 3 additions & 0 deletions app/assets/images/send.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions app/controllers/expenses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ def destroy
redirect_to club_expenses_url(@club), flash: { success: I18n.t('expenses.destroyed') }
end

def send_receipt
@expense = @club.expenses.find(params[:expense_id])

ReceiptMailer.with(expense: @expense).collaborator_receipt_email.deliver_later

redirect_to club_expenses_url(@club), flash: { notice: I18n.t('expenses.receipt_sent') }
end

private

def expense_params
Expand Down
10 changes: 9 additions & 1 deletion app/controllers/payments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def index
end

def new
@payment = @member.payments.new
@payment = @member.payments.new(number: @club.payments.maximum(:number))
end

def edit
Expand Down Expand Up @@ -49,6 +49,14 @@ def destroy
redirect_to club_payments_url(@club), flash: { success: I18n.t('payments.destroyed') }
end

def send_receipt
@payment = @club.payments.find(params[:payment_id])

ReceiptMailer.with(payment: @payment).member_receipt_email.deliver_later

redirect_to club_payments_url(@club), flash: { notice: I18n.t('payments.receipt_sent') }
end

private

def payment_params
Expand Down
23 changes: 23 additions & 0 deletions app/mailers/receipt_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

class ReceiptMailer < ApplicationMailer
def collaborator_receipt_email
@expense = params[:expense]

generator = Pdf::CollaboratorsReceiptGenerator.new(expense: @expense)
pdf_path = generator.call

attachments['receipt.pdf'] = File.read(pdf_path)
mail(to: @expense.user.email, subject: I18n.t('expenses.collaborator_email.subject'))
end

def member_receipt_email
@payment = params[:payment]

generator = Pdf::MembersReceiptGenerator.new(payment: @payment)
pdf_path = generator.call

attachments['receipt.pdf'] = File.read(pdf_path)
mail(to: @payment.member.email, subject: I18n.t('payments.member_email.subject'))
end
end
11 changes: 10 additions & 1 deletion app/models/club.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

class Club < ApplicationRecord
has_one_attached :picture
validates :picture, content_type: ['image/png', 'image/jpeg']
validates :picture, content_type: ['image/png', 'image/jpeg', 'image/webp']

has_many :users, dependent: :destroy

Expand All @@ -22,4 +22,13 @@ class Club < ApplicationRecord

normalizes :email, with: ->(v) { v.strip.downcase }
normalizes :province, with: ->(v) { v.upcase }

def full_name_and_address_for_receipt
[name, full_address, email].join('<br/>')
end

# TODO
def full_address
'via Roma 139, Livorno'
end
end
5 changes: 5 additions & 0 deletions app/models/expense.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

class Expense < ApplicationRecord
belongs_to :club
belongs_to :user, optional: true
belongs_to :expense_reason

validates :amount, presence: true

def in_eur
"#{(amount / 100.0).round(2)} €"
end
end
11 changes: 10 additions & 1 deletion app/models/payment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,14 @@ class Payment < ApplicationRecord
belongs_to :member
belongs_to :payment_reason

validates :amount, presence: true
validates :amount, :number, :kind, presence: true
validates :number, uniqueness: { conditions: -> { of_year(Time.current.year) } }

enum :kind, %i[cash bank other]

scope :of_year, ->(year) { where(created_at: "#{year}-01-01".to_date.all_year) }

def in_eur
"#{(amount / 100.0).round(2)} €"
end
end
5 changes: 5 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class User < ApplicationRecord

has_many :user_groups, dependent: :destroy
has_many :groups, through: :user_groups, dependent: :nullify
has_many :expenses, dependent: :nullify

enum :role, %i[admin collaborator]

Expand All @@ -32,4 +33,8 @@ class User < ApplicationRecord
def admin?
role == 'admin'
end

def full_name
"#{last_name} #{first_name}".capitalize
end
end
37 changes: 37 additions & 0 deletions app/services/pdf/collaborators_receipt_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

module Pdf
class CollaboratorsReceiptGenerator
attr_reader :club, :user, :expense

def initialize(expense:)
@expense = expense
@user = expense.user

raise 'Expense is without collaborator!' unless @user

@club = @user.club
end

def call
path = Rails.root.join('tmp', filename)
template = Rails.root.join('app/views/pdf/expenses/compensation.html.erb')

html = ERB.new(template.read).result(binding)

kit = PDFKit.new(
html,
page_size: 'A4', orientation: 'portrait',
margin_top: '5mm', margin_bottom: '5mm',
margin_left: '5mm', margin_right: '5mm'
)
kit.to_file(path)

path
end

def filename
"pdf_#{expense.id}.pdf"
end
end
end
34 changes: 34 additions & 0 deletions app/services/pdf/members_receipt_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

module Pdf
class MembersReceiptGenerator
attr_reader :club, :member, :payment

def initialize(payment:)
@payment = payment
@member = payment.member
@club = @member.club
end

def call
path = Rails.root.join('tmp', filename)
template = Rails.root.join('app/views/pdf/payments/receipt.html.erb')

html = ERB.new(template.read).result(binding)

kit = PDFKit.new(
html,
page_size: 'A4', orientation: 'portrait',
margin_top: '5mm', margin_bottom: '5mm',
margin_left: '5mm', margin_right: '5mm'
)
kit.to_file(path)

path
end

def filename
"pdf_#{payment.id}.pdf"
end
end
end
3 changes: 1 addition & 2 deletions app/views/application/_footer.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,5 @@
(function (w,d) {var loader = function () {var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0]; s.src="https://cdn.iubenda.com/iubenda.js"; tag.parentNode.insertBefore(s,tag);}; if(w.addEventListener){w.addEventListener("load", loader, false);}else if(w.attachEvent){w.attachEvent("onload", loader);}else{w.onload = loader;}})(window, document);
</script>
</div>
</div>
</footer>
</footer>
</div>
12 changes: 5 additions & 7 deletions app/views/blsd_mailer/expiring_email.html.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
<%= I18n.t('blsd.expiring_email.hello') %>
<%= @member.first_name %>

<br><br>

<%= @member.first_name %>
<br>
<br>
<%= I18n.t('blsd.expiring_email.expiring_text') %>

<br><br>

<br>
<br>
<%= I18n.t('blsd.expiring_email.remember_text') %>
4 changes: 2 additions & 2 deletions app/views/expense_reasons/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
<tr>
<td><%= expense_reason.reason %></td>
<td>
<%= link_to edit_club_expense_reason_path(@club, expense_reason) do %>
<%= link_to edit_club_expense_reason_path(@club, expense_reason), class: 'text-decoration-none' do %>
<%= image_tag "edit.svg", aria: { hidden: true }, size: 24 %>
<% end %>
<%= link_to club_expense_reason_path(@club, expense_reason), data: { turbo_method: :delete, turbo_confirm: 'Are you sure?'} do %>
<%= link_to club_expense_reason_path(@club, expense_reason), data: { turbo_method: :delete, turbo_confirm: 'Are you sure?'}, class: 'text-decoration-none' do %>
<%= image_tag "trash.svg", aria: { hidden: true }, size: 24 %>
<% end %>
</td>
Expand Down
9 changes: 7 additions & 2 deletions app/views/expenses/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,15 @@
<td><%= expense.expense_reason.reason %></td>
<td><%= expense.created_at %></td>
<td>
<%= link_to edit_club_expense_path(@club, expense) do %>
<% if expense.user.present? %>
<%= link_to club_expense_send_receipt_path(@club, expense), data: { turbo_method: :get, turbo_confirm: I18n.t('expenses.confirm_send')}, class: 'text-decoration-none' do %>
<%= image_tag "send.svg", aria: { hidden: true }, size: 24 %>
<% end %>
<% end %>
<%= link_to edit_club_expense_path(@club, expense), class: 'text-decoration-none' do %>
<%= image_tag "edit.svg", aria: { hidden: true }, size: 24 %>
<% end %>
<%= link_to club_expense_path(@club, expense), data: { turbo_method: :delete, turbo_confirm: 'Are you sure?'} do %>
<%= link_to club_expense_path(@club, expense), data: { turbo_method: :delete, turbo_confirm: I18n.t('expenses.confirm_destroy')}, class: 'text-decoration-none' do %>
<%= image_tag "trash.svg", aria: { hidden: true }, size: 24 %>
<% end %>
</td>
Expand Down
4 changes: 2 additions & 2 deletions app/views/groups/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
<td><%= number_to_currency(group.default_amount) %></td>
<td><%= group.mandatory_medical_certificate %></td>
<td>
<%= link_to edit_club_group_path(@club, group) do %>
<%= link_to edit_club_group_path(@club, group), class: 'text-decoration-none' do %>
<%= image_tag "edit.svg", aria: { hidden: true }, size: 24 %>
<% end %>
<%= link_to club_group_path(@club, group), data: { turbo_method: :delete, turbo_confirm: 'Are you sure?'} do %>
<%= link_to club_group_path(@club, group), data: { turbo_method: :delete, turbo_confirm: 'Are you sure?'}, class: 'text-decoration-none' do %>
<%= image_tag "trash.svg", aria: { hidden: true }, size: 24 %>
<% end %>
</td>
Expand Down
12 changes: 5 additions & 7 deletions app/views/medical_certificate_mailer/expiring_email.html.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
<%= I18n.t('medical_certificate.expiring_email.hello') %>
<%= @member.first_name %>

<br><br>

<%= @member.first_name %>
<br>
<br>
<%= I18n.t('medical_certificate.expiring_email.expiring_text') %>

<br><br>

<br>
<br>
<%= I18n.t('medical_certificate.expiring_email.remember_text') %>
Loading

0 comments on commit a718e90

Please sign in to comment.