require "prawn/measurement_extensions" module Dorsale module BillingMachine class InvoiceSingleVatPdf < Prawn::Document include Dorsale::Alexandrie::Prawn include Dorsale::AllHelpers include ActionView::Helpers::NumberHelper DEBUG = false GREY = "808080" LIGHT_GREY = "C0C0C0" WHITE = "FFFFFF" BLACK = "000000" BLUE = "005F9E" def has_advance @main_document.try(:advance) && @main_document.advance != 0.0 end def has_discount @main_document.try(:commercial_discount) && @main_document.commercial_discount != 0.0 end def first_column_width 7.6.cm end def second_column_width 2.4.cm end def third_column_width second_column_width end def fourth_column_width 2.9.cm end def last_column_width bounds.width - first_column_width - second_column_width - third_column_width - fourth_column_width end attr_reader :main_document def initialize(main_document) super(page_size: 'A4', margin: 1.cm) setup @main_document = main_document @id_card = main_document.id_card end def header_height 9.cm end def middle_height 15.cm end def footer_height 4.cm end def logo_height 3.2.cm end def build repeat :all do build_header build_footer end build_middle build_page_numbers end def setup font_root = ::Dorsale::Engine.root.join("app/assets/fonts") font_families.update( "BryantPro" => { normal: "#{font_root}/BryantPro-Regular.ttf", bold: "#{font_root}/BryantPro-Bold.ttf", } ) font("BryantPro") font_size 10 end def build_header bounding_box [0, bounds.top], width: bounds.width, height: header_height do draw_bounds_debug build_title build_logo build_contact build_subject build_customer end end def build_title top = bounds.top - 1.5.cm left = bounds.left width = bounds.width height = 1.cm bounding_box [left, top], width: width, height: height do draw_bounds_debug text "#{main_document_type}", inline_format: true, size: 20, align: :center end end def build_logo width = 3.2.cm height = logo_height bounding_box [bounds.left, bounds.top], width: width, height: height do draw_bounds_debug if @main_document.id_card.logo.present? image @main_document.id_card.logo.path, width: (bounds.width - 1.cm) end end end def address_line [@id_card.address1,@id_card.address2, @id_card.zip, @id_card.city].select(&:present?).join(", ") end def build_contact top = bounds.top - 4.cm left = bounds.left width = bounds.width / 2 - 1.1.cm height = 2.5.cm bounding_box [left, top], width: width, height: height do draw_bounds_debug font_size 8 do text "#{@id_card.entity_name}", inline_format: true if @id_card.entity_name.present? text "#{address_line} ", inline_format: true text " " text "#{I18n.t("pdfs.your_contact")} : #{@id_card.contact_full_name}", inline_format: true if @id_card.contact_full_name.present? text "#{I18n.t("pdfs.contact_phone")} #{@id_card.contact_phone}", inline_format: true if @id_card.contact_phone.present? text "#{I18n.t("pdfs.contact_fax")} #{@id_card.contact_fax}", inline_format: true if @id_card.contact_fax.present? text "#{I18n.t("pdfs.contact_email")} #{@id_card.contact_email}", inline_format: true if @id_card.contact_email.present? end end end def build_subject top = bounds.top - 7.5.cm left = bounds.left width = bounds.width / 2 - 1.1.cm height = 1.cm bounding_box [left, top], width: width, height: height do draw_bounds_debug text "#{I18n.t("pdfs.subject")} #{@main_document.label}", inline_format: true if @main_document.label.present? end end def build_customer top = bounds.top - 4.cm left = bounds.width / 2 + 1.1.cm width = bounds.width / 2 - 1.1.cm height = 4.5.cm bounding_box [left, top], width: width, height: height do draw_bounds_debug stroke do fill_color LIGHT_GREY fill_rounded_rectangle [cursor-bounds.height,cursor], bounds.width, bounds.height, 0 fill_color BLACK end table_customer = [] if @main_document.tracking_id.present? table_customer << [I18n.t("pdfs.tracking_number") , @main_document.tracking_id.to_s] end if @main_document.date.present? table_customer << [I18n.t("pdfs.date") , date(@main_document.date)] end if @main_document.customer.present? name = "#{@main_document.customer.name}\n" if @main_document.customer.name.present? street = "#{@main_document.customer.address.street}\n" if @main_document.customer.address.street? street_bis = "#{@main_document.customer.address.street_bis}\n" if @main_document.customer.address.street_bis.present? zip_country = "#{@main_document.customer.address.zip} #{@main_document.customer.address.city}" if @main_document.customer.address.city.present? table_customer << [I18n.t("pdfs.customer") , "#{name} #{street} #{street_bis} #{zip_country}" ] if @main_document.customer.name.present? end table table_customer, :column_widths => [ width / 3 , width - (width / 3)], :cell_style => {border_width: [0, 0, 0.5, 0], padding: [2.mm, 2.mm]} do row(2).border_width = 0 column(0).font_style = :bold column(1).row(2).valign = :center end end end def build_middle left = bounds.left top = bounds.top - header_height width = bounds.width - left bounding_box [left, top], width: width, height: middle_height do build_table build_total build_payment_conditions build_bank_informations build_expiry build_comments end end def main_document_type Dorsale::BillingMachine::Invoice.model_name.human.humanize end def build_table left = bounds.left top = bounds.top width = bounds.width - left bounding_box [left, top], width: width, height: 9.5.cm do repeat :all do float do table [["","","","",""]], :column_widths => [first_column_width, second_column_width, third_column_width, fourth_column_width, last_column_width], :cell_style => {:height => 9.5.cm} do row(0).style :text_color => BLACK row(0).style :font_style => :bold column(0).style :align => :left column(1..4).style :align => :right end end end end bounding_box [left, top], width: width, height: 8.8.cm do draw_bounds_debug repeat :all do build_line end table_products = [[I18n.t("pdfs.designation"), I18n.t("pdfs.quantity"), I18n.t("pdfs.unity"), I18n.t("pdfs.unit_price"), I18n.t("pdfs.line_total")]] @main_document.lines.each do |line| table_products.push [line.label, number(line.quantity).gsub(",00","").gsub(".00",""), line.unit, euros(line.unit_price), euros(line.total),] end table table_products, :column_widths => [first_column_width, second_column_width, third_column_width, fourth_column_width, last_column_width], :header => true, :cell_style => {border_width: 0} do row(0).font_style = :bold row(0).border_width = 1, cells.style do |c| c.align = c.column == 0 ? :left : :right end end end end def build_total left = bounds.left top = bounds.top - 10.3.cm width = bounds.width - left bounding_box [left, top], width: width, height: middle_height - 9.5.cm do draw_bounds_debug table_totals = [[]] if has_discount table_totals.push ["#{I18n.t("pdfs.commercial_discount")}", "\- #{euros(@main_document.commercial_discount)}"] end table_totals.push ["#{I18n.t("pdfs.total_excluding_taxes")}", euros(@main_document.total_excluding_taxes)] vat_rate = number(@main_document.vat_rate) table_totals.push ["#{I18n.t("pdfs.vat")}#{vat_rate} %", euros(@main_document.vat_amount)] if has_advance table_totals.push ["#{I18n.t("pdfs.advance")}", euros(@main_document.advance)] table_totals.push ["#{I18n.t("pdfs.total_including_taxes")}", euros(@main_document.balance)] else table_totals.push ["#{I18n.t("pdfs.total_including_taxes")}", euros(@main_document.total_including_taxes)] end table table_totals, :column_widths => [fourth_column_width, last_column_width], :cell_style => {border_width: [0, 1, 0 ,0]}, :position => :right do row(-1).style :font_style => :bold column(0).padding_right = 0.2.cm row(-1).borders = [:top, :right] row(-1).border_width = 1 cells.style do |c| c.align = :right end end stroke do rectangle [(bounds.right - fourth_column_width - last_column_width), bounds.top], (fourth_column_width + last_column_width), (bounds.top-cursor) end end end def build_comments end def build_payment_conditions top = bounds.top - 10.3.cm height = 1.cm width = 7.5.cm bounding_box [bounds.left, top], height: height, width: width do draw_bounds_debug font_size 9 do text I18n.t("pdfs.payment_terms"), style: :bold if @main_document.payment_term.present? text @main_document.payment_term.try(:label) end end end def build_expiry end def build_bank_informations top = bounds.top - 11.5.cm height = 1.cm width = 7.5.cm bounding_box [bounds.left, top], height: height, width: width do draw_bounds_debug font_size 9 do text "#{I18n.t("pdfs.iban")} #{@id_card.iban}" if @id_card.iban.present? text "#{I18n.t("pdfs.bic_swift")} #{@id_card.bic_swift}" if @id_card.bic_swift.present? end end end def build_footer top = bounds.bottom + footer_height bounding_box [0, top], width: bounds.width, height: footer_height do builds_legals build_line builds_id_card_informations end end def builds_legals top = bounds.top height = 1.5.cm width = bounds.width bounding_box [bounds.left, top], height: height, width: width do font_size 9 do text @id_card.custom_info_1, inline_format: true end end end def build_line stroke do horizontal_rule line_width 1 end end def builds_id_card_informations top = bounds.top - 1.8.cm height = 1.1.cm width = bounds.width tel = "#{I18n.t("pdfs.info_phone")} #{@id_card.contact_phone} - " if @id_card.contact_phone.present? fax = "#{I18n.t("pdfs.info_fax")} #{@id_card.contact_fax} -" if @id_card.contact_fax.present? email = "#{@id_card.contact_email}" if @id_card.contact_email.present? capital = "#{ @id_card.legal_form.to_s} #{I18n.t("pdfs.capital")} " + number_with_delimiter(@id_card.capital, :delimiter => '.').to_s + " €" if @id_card.legal_form.present? && @id_card.capital.present? registration = I18n.t("pdfs.registration") + @id_card.registration_city.to_s + ' ' + @id_card.registration_number.to_s if @id_card.registration_number.present? siret = I18n.t("pdfs.siret") + @id_card.siret.to_s if @id_card.siret.present? tva = I18n.t("pdfs.vat") + @id_card.intracommunity_vat.to_s if @id_card.intracommunity_vat.present? font_size 9 do text_box "#{@id_card.entity_name} #{address_line}\n#{tel} #{fax} #{email}\n#{capital} #{registration} #{siret} #{tva}", :at => [bounds.left, top], :height => height, :width => width, :overflow => :shrink_to_fit end end def build_page_numbers top = bounds.bottom + footer_height - 1.8.cm bounding_box [0, top], height: footer_height, width: bounds.width do font_size 9 do float do options = { :align => :right, :start_count_at => 1 } number_pages "page /", options end end end end def draw_bounds_debug transparent(0.5) { stroke_bounds } if DEBUG end end end end