Created
April 21, 2011 19:18
-
-
Save romuloceccon/935279 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
require 'rubygems' | |
require 'prawn' | |
require 'benchmark' | |
class Danfe | |
# Largura mínima da barra deve ser de 6 cm / 297 = 0,02 cm = 0,57 pt. A largura que usaremos | |
# será 0,70 pt = 0,025 cm = 7,33 cm / 297. | |
BAR_WIDTH = 0.7 | |
PAGE_SIZE = 'A4' | |
MARGIN = [20, 20, 20, 20] | |
MAX_WIDTH = Prawn::Document::PageGeometry::SIZES[PAGE_SIZE][0] - (MARGIN[1] + MARGIN[3]) | |
MAX_HEIGTH = Prawn::Document::PageGeometry::SIZES[PAGE_SIZE][1] - (MARGIN[0] + MARGIN[2]) | |
LINE_WIDTH = 0.3 | |
TEXT_BOX_RADIUS = 2 | |
TEXT_BOX_HEIGTH = 20 | |
LABEL_SIZE = 6 | |
TEXT_SIZE = 10 | |
SECTION_SPACING = LABEL_SIZE + 4 | |
class Code128C | |
START_CODE_C = 105 | |
STOP_CODE = 106 | |
MODULO = 103 | |
TABLE = [ | |
[2, 1, 2, 2, 2, 2], | |
[2, 2, 2, 1, 2, 2], | |
[2, 2, 2, 2, 2, 1], | |
[1, 2, 1, 2, 2, 3], | |
[1, 2, 1, 3, 2, 2], | |
[1, 3, 1, 2, 2, 2], | |
[1, 2, 2, 2, 1, 3], | |
[1, 2, 2, 3, 1, 2], | |
[1, 3, 2, 2, 1, 2], | |
[2, 2, 1, 2, 1, 3], | |
[2, 2, 1, 3, 1, 2], | |
[2, 3, 1, 2, 1, 2], | |
[1, 1, 2, 2, 3, 2], | |
[1, 2, 2, 1, 3, 2], | |
[1, 2, 2, 2, 3, 1], | |
[1, 1, 3, 2, 2, 2], | |
[1, 2, 3, 1, 2, 2], | |
[1, 2, 3, 2, 2, 1], | |
[2, 2, 3, 2, 1, 1], | |
[2, 2, 1, 1, 3, 2], | |
[2, 2, 1, 2, 3, 1], | |
[2, 1, 3, 2, 1, 2], | |
[2, 2, 3, 1, 1, 2], | |
[3, 1, 2, 1, 3, 1], | |
[3, 1, 1, 2, 2, 2], | |
[3, 2, 1, 1, 2, 2], | |
[3, 2, 1, 2, 2, 1], | |
[3, 1, 2, 2, 1, 2], | |
[3, 2, 2, 1, 1, 2], | |
[3, 2, 2, 2, 1, 1], | |
[2, 1, 2, 1, 2, 3], | |
[2, 1, 2, 3, 2, 1], | |
[2, 3, 2, 1, 2, 1], | |
[1, 1, 1, 3, 2, 3], | |
[1, 3, 1, 1, 2, 3], | |
[1, 3, 1, 3, 2, 1], | |
[1, 1, 2, 3, 1, 3], | |
[1, 3, 2, 1, 1, 3], | |
[1, 3, 2, 3, 1, 1], | |
[2, 1, 1, 3, 1, 3], | |
[2, 3, 1, 1, 1, 3], | |
[2, 3, 1, 3, 1, 1], | |
[1, 1, 2, 1, 3, 3], | |
[1, 1, 2, 3, 3, 1], | |
[1, 3, 2, 1, 3, 1], | |
[1, 1, 3, 1, 2, 3], | |
[1, 1, 3, 3, 2, 1], | |
[1, 3, 3, 1, 2, 1], | |
[3, 1, 3, 1, 2, 1], | |
[2, 1, 1, 3, 3, 1], | |
[2, 3, 1, 1, 3, 1], | |
[2, 1, 3, 1, 1, 3], | |
[2, 1, 3, 3, 1, 1], | |
[2, 1, 3, 1, 3, 1], | |
[3, 1, 1, 1, 2, 3], | |
[3, 1, 1, 3, 2, 1], | |
[3, 3, 1, 1, 2, 1], | |
[3, 1, 2, 1, 1, 3], | |
[3, 1, 2, 3, 1, 1], | |
[3, 3, 2, 1, 1, 1], | |
[3, 1, 4, 1, 1, 1], | |
[2, 2, 1, 4, 1, 1], | |
[4, 3, 1, 1, 1, 1], | |
[1, 1, 1, 2, 2, 4], | |
[1, 1, 1, 4, 2, 2], | |
[1, 2, 1, 1, 2, 4], | |
[1, 2, 1, 4, 2, 1], | |
[1, 4, 1, 1, 2, 2], | |
[1, 4, 1, 2, 2, 1], | |
[1, 1, 2, 2, 1, 4], | |
[1, 1, 2, 4, 1, 2], | |
[1, 2, 2, 1, 1, 4], | |
[1, 2, 2, 4, 1, 1], | |
[1, 4, 2, 1, 1, 2], | |
[1, 4, 2, 2, 1, 1], | |
[2, 4, 1, 2, 1, 1], | |
[2, 2, 1, 1, 1, 4], | |
[4, 1, 3, 1, 1, 1], | |
[2, 4, 1, 1, 1, 2], | |
[1, 3, 4, 1, 1, 1], | |
[1, 1, 1, 2, 4, 2], | |
[1, 2, 1, 1, 4, 2], | |
[1, 2, 1, 2, 4, 1], | |
[1, 1, 4, 2, 1, 2], | |
[1, 2, 4, 1, 1, 2], | |
[1, 2, 4, 2, 1, 1], | |
[4, 1, 1, 2, 1, 2], | |
[4, 2, 1, 1, 1, 2], | |
[4, 2, 1, 2, 1, 1], | |
[2, 1, 2, 1, 4, 1], | |
[2, 1, 4, 1, 2, 1], | |
[4, 1, 2, 1, 2, 1], | |
[1, 1, 1, 1, 4, 3], | |
[1, 1, 1, 3, 4, 1], | |
[1, 3, 1, 1, 4, 1], | |
[1, 1, 4, 1, 1, 3], | |
[1, 1, 4, 3, 1, 1], | |
[4, 1, 1, 1, 1, 3], | |
[4, 1, 1, 3, 1, 1], | |
[1, 1, 3, 1, 4, 1], | |
[1, 1, 4, 1, 3, 1], | |
[3, 1, 1, 1, 4, 1], | |
[4, 1, 1, 1, 3, 1], | |
[2, 1, 1, 4, 1, 2], | |
[2, 1, 1, 2, 1, 4], | |
[2, 1, 1, 2, 3, 2], | |
[2, 3, 3, 1, 1, 1, 2] | |
] | |
def self.to_code_128c(str) | |
arr = str.scan(/\d{2}/).map { |x| x.to_i } | |
arr.unshift(START_CODE_C) | |
sum = START_CODE_C | |
arr.each_with_index { |x, i| sum += x * i } | |
arr << sum % MODULO | |
arr << STOP_CODE | |
arr.map { |x| TABLE[x] }.flatten | |
end | |
def self.draw_bar_code_128c(str, options) | |
min_width = options[:min_width] | |
total_width = options[:total_width] | |
start_pos = options[:start_pos] | |
bar_code = to_code_128c(str) | |
seg_count = bar_code.inject { |a, b| a + b } | |
x = start_pos + (total_width - seg_count * min_width) / 2.0 | |
bar = true | |
bar_code.each do |w| | |
if bar | |
yield(x, w * min_width) | |
end | |
x += w * min_width | |
bar = !bar | |
end | |
end | |
end | |
class Layout | |
attr_reader :pdf | |
attr_accessor :x | |
public | |
def initialize | |
@pdf = Prawn::Document.new(:page_size => PAGE_SIZE, :margin => MARGIN) | |
@pdf.font('Times-Roman') | |
@pdf.line_width = LINE_WIDTH | |
@x = 0 | |
@pdf.move_down(MARGIN[2]) | |
end | |
def start_new_page | |
@pdf.start_new_page | |
@pdf.move_down(MARGIN[2]) | |
end | |
def write(file_name) | |
@pdf.close_and_stroke | |
@pdf.render_file(file_name) | |
end | |
def text_box_with_box(label, text, width, height = nil, options = {}) | |
@pdf.rounded_rectangle([@x, y], width, height || TEXT_BOX_HEIGTH, TEXT_BOX_RADIUS) | |
@pdf.text_box(label, :size => LABEL_SIZE, :at => [@x + 2, y - 2], :width => width - 2, | |
:height => LABEL_SIZE, :valign => :top) | |
h_text = height.nil? ? TEXT_SIZE : height - LABEL_SIZE - 4 | |
@pdf.text_box(text, { :size => TEXT_SIZE, :at => [@x + 2, y - LABEL_SIZE - 4], | |
:width => width - 2, :height => h_text, :valign => :top }.merge(options)) | |
@x += width | |
end | |
def header_cell(text, width, align = :left) | |
t = Prawn::Text::Box.new(text, :size => LABEL_SIZE, :at => [@x + 1, y], | |
:width => abs_width(width) - 2, :align => align, :document => @pdf) | |
t.render | |
@x += abs_width(width) | |
t.height | |
end | |
def cell(text, width, align = :left, options = {}) | |
dry_run = options.delete(:dry_run) | |
t = Prawn::Text::Box.new(text, options.merge({ :at => [@x + 1, y], | |
:width => abs_width(width) - 2, :align => align, :document => @pdf })) | |
t.render(:dry_run => dry_run) | |
@x += abs_width(width) unless dry_run | |
t.height | |
end | |
def text_box(text, params = {}) | |
t = Prawn::Text::Box.new(text, params.merge({ :document => @pdf })) | |
t.render | |
t.height | |
end | |
def receipt_box(label, content, start, stop) | |
unless content.empty? | |
@pdf.text_box(content, :size => 10, :at => [MAX_WIDTH * start, y - 21], | |
:width => MAX_WIDTH * (stop - start), :align => :center) | |
end | |
@pdf.text_box(label, :size => 6, :at => [MAX_WIDTH * start, y - 33], | |
:width => MAX_WIDTH * (stop - start), :align => :center) | |
@pdf.horizontal_line(MAX_WIDTH * start, MAX_WIDTH * stop, :at => y - 30) | |
end | |
def cell_break | |
@x = 0 | |
@pdf.move_down(10) | |
end | |
def space(width) | |
@x += width | |
end | |
def line_break | |
@x = 0 | |
@pdf.move_down(TEXT_BOX_HEIGTH) | |
end | |
def row | |
@x = 0 | |
@pdf.pad_bottom(TEXT_BOX_HEIGTH) do | |
yield Row.new(self) | |
end | |
end | |
def section(name, options = {}) | |
at = options[:at] | |
old_y = y | |
@pdf.move_cursor_to(at - MARGIN[2]) if at | |
begin | |
@x = 0 | |
@pdf.pad_bottom(SECTION_SPACING) do | |
@pdf.text_box(name, :size => LABEL_SIZE, :style => :bold, :at => [0, y - 4], | |
:width => MAX_WIDTH, :height => LABEL_SIZE, :valign => :top) | |
end | |
yield | |
ensure | |
@pdf.move_cursor_to(old_y) if at | |
end | |
end | |
def abs_width(x) | |
x / 100.0 * MAX_WIDTH | |
end | |
def y | |
@pdf.y | |
end | |
def move_down(v) | |
@pdf.move_down(v) | |
end | |
def table(headers, data, widths, align, cell_options = {}, table_options = {}) | |
move_down(2) | |
y0 = y | |
h = 0 | |
@x = 0 | |
widths.each_with_index do |w, i| | |
h = [header_cell(headers[i], w, :center), h].max | |
end | |
heigth_calc = table_options[:heigth_calc] | |
min_y = table_options[:min_y] || 0.0 | |
while !data.empty? | |
r = data.first | |
if heigth_calc | |
h_calc = cell(r[heigth_calc], widths[heigth_calc], align[heigth_calc], cell_options.merge({ :dry_run => true })) | |
#print y - (h + 1 + 3 + h_calc + 1), ' < ', min_y, "\n" | |
if y - (h + 1 + 3 + h_calc + 1) < min_y | |
break | |
end | |
end | |
@pdf.pad_top(h + 1) do | |
@pdf.horizontal_line(0, abs_width(100), :at => y) | |
end | |
move_down(3) | |
h = 0 | |
@x = 0 | |
widths.each_with_index do |w, i| | |
h = [cell(r[i] || '', w, align[i], cell_options), h].max | |
end | |
data.shift | |
end | |
move_down(h + 1) | |
y1 = y | |
@pdf.stroke do | |
widths.inject do |sum, x| | |
@pdf.vertical_line(y0 + 2, y1, :at => abs_width(sum)) | |
sum + x | |
end | |
@pdf.rounded_rectangle([0, y0 + 2], MAX_WIDTH, y0 - y1 + 2, TEXT_BOX_RADIUS) | |
end | |
#puts y | |
end | |
class Row | |
def initialize(layout) | |
@layout = layout | |
end | |
def text_box_with_box(relative_width, label, text) | |
@layout.text_box_with_box(label, text, abs_width(relative_width)) | |
end | |
def space(relative_width) | |
@layout.space(abs_width(relative_width)) | |
end | |
private | |
def abs_width(relative_width) | |
if relative_width == :max | |
MAX_WIDTH - @layout.x | |
else | |
relative_width / 100.0 * MAX_WIDTH | |
end | |
end | |
end | |
end | |
def initialize(data) | |
@layout = Layout.new | |
@page_infos = [] | |
@data = data | |
@chave = data[:chave_nfe_formatada] | |
@bar_code_box_width = 2 + @layout.pdf.width_of(@chave, :size => 9, :style => :bold) | |
@formulario_seguranca = !@data[:formulario_seguranca].to_i.zero? | |
@fs_warning_height = @formulario_seguranca ? 20 : 0 | |
end | |
def columnize_array(arr, count) | |
lines = (arr.count + count - 1) / count | |
item_len = arr.first.count | |
(0...lines).map do |line| | |
(0...count).map { |i| arr[i * count + line] || [nil] * item_len }.flatten | |
end | |
end | |
def draw_header | |
hs = 83 | |
hq = hp = nil | |
@layout.pdf.stroke do | |
@page_infos[@layout.pdf.page_number - 1] = { :center_box_top => @layout.y } | |
emitente_box_width = MAX_WIDTH * (1 - 0.02 - 0.20) - @bar_code_box_width | |
@layout.pdf.rounded_rectangle([0, @layout.y], emitente_box_width, hs - 2, | |
TEXT_BOX_RADIUS) | |
logo_width = 72 | |
img = Prawn::Images::PNG.new(File.binread(@data[:nome_logo])) | |
@layout.pdf.image(@data[:nome_logo], :at => [(logo_width - img.width * 0.24) / 2.0, | |
@layout.y - (hs - 2 - img.height * 0.24) / 2.0], :scale => 0.24) | |
i1 = @layout.y - 4 | |
i1 -= @layout.text_box(@data[:nome_emitente], :style => :bold, :size => 12, | |
:at => [logo_width, i1], :width => emitente_box_width - logo_width, :align => :left) | |
i1 -= 6 | |
i1 -= @layout.text_box(@data[:dados_emitente], | |
:style => :bold, :size => 8, :at => [logo_width, i1], :width => emitente_box_width - logo_width, :align => :left) | |
i1 -= 2 | |
hx = hs + 6 + 2 * TEXT_BOX_HEIGTH | |
@layout.pdf.rounded_rectangle([MAX_WIDTH - @bar_code_box_width, @layout.y], | |
@bar_code_box_width, hx, TEXT_BOX_RADIUS) | |
hq = @layout.y - (hx - 2 * TEXT_BOX_HEIGTH) / 2 | |
@layout.pdf.horizontal_line(MAX_WIDTH - @bar_code_box_width, MAX_WIDTH, :at => hq) | |
@layout.text_box("CHAVE DE ACESSO", :size => LABEL_SIZE, | |
:at => [MAX_WIDTH - @bar_code_box_width + 2, hq - 2]) | |
@layout.text_box(@chave, :size => 9, :style => :bold, | |
:at => [MAX_WIDTH - @bar_code_box_width, hq - 10], :width => @bar_code_box_width, :align => :center) | |
@layout.pdf.horizontal_line(MAX_WIDTH - @bar_code_box_width, MAX_WIDTH, :at => hq - TEXT_BOX_HEIGTH) | |
unless @formulario_seguranca | |
@layout.text_box("Consulta de autenticidade no portal nacional\nda NF-e (www.nfe.fazenda.gov.br/portal)\nou no site da Sefaz Autorizadora", | |
:size => 9, :style => :bold, :width => @bar_code_box_width, :align => :center, | |
:valign => :center, :at => [MAX_WIDTH - @bar_code_box_width, hq - TEXT_BOX_HEIGTH], | |
:height => (hx - 2 * TEXT_BOX_HEIGTH) / 2) | |
end | |
hp = @layout.y - (hx - TEXT_BOX_HEIGTH) | |
@layout.pdf.horizontal_line(MAX_WIDTH - @bar_code_box_width, MAX_WIDTH, :at => hp) | |
@layout.text_box(@data[:titulo_dados_nfe], :size => LABEL_SIZE, | |
:at => [MAX_WIDTH - @bar_code_box_width + 2, hp - 2]) | |
@layout.text_box(@data[:conteudo_dados_nfe], :size => 9, :style => :bold, | |
:at => [MAX_WIDTH - @bar_code_box_width, hp - 10], :width => @bar_code_box_width, :align => :center) | |
end | |
bar_code_height = @layout.y - hq | |
bar_code_y0 = hq + bar_code_height * 0.85 | |
bar_code_y1 = hq + bar_code_height * 0.15 | |
Code128C.draw_bar_code_128c(@chave, :min_width => BAR_WIDTH, :total_width => @bar_code_box_width, | |
:start_pos => MAX_WIDTH - @bar_code_box_width) do |x, w| | |
@layout.pdf.stroke do | |
@layout.pdf.line_width = w | |
@layout.pdf.vertical_line(bar_code_y0, bar_code_y1, :at => x + w / 2.0) | |
end | |
end | |
bar_code_y0 = hp + bar_code_height * 0.85 | |
bar_code_y1 = hp + bar_code_height * 0.15 | |
if @formulario_seguranca | |
Code128C.draw_bar_code_128c(@data[:conteudo_dados_nfe], | |
:min_width => BAR_WIDTH, :total_width => @bar_code_box_width, | |
:start_pos => MAX_WIDTH - @bar_code_box_width) do |x, w| | |
@layout.pdf.stroke do | |
@layout.pdf.line_width = w | |
@layout.pdf.vertical_line(bar_code_y0, bar_code_y1, :at => x + w / 2.0) | |
end | |
end | |
end | |
@layout.pdf.line_width = LINE_WIDTH | |
@layout.move_down(hs + 6) | |
natureza_operacao_width = 99 - @bar_code_box_width / MAX_WIDTH * 100 | |
@layout.row do |r| | |
r.text_box_with_box(natureza_operacao_width, 'NATUREZA DE OPERAÇÃO', @data[:natureza_operacao]) | |
end | |
@layout.row do |r| | |
r.text_box_with_box(natureza_operacao_width / 3, 'INSCRIÇÃO ESTADUAL', @data[:inscricao_estadual_emitente]) | |
r.text_box_with_box(natureza_operacao_width / 3, 'INSCR. ESTADUAL DO SUBST.', @data[:inscricao_estadual_st_emitente]) | |
r.text_box_with_box(natureza_operacao_width / 3, 'CNPJ', @data[:cnpj_emitente]) | |
end | |
end | |
def draw_center_info | |
center_info_left = MAX_WIDTH * (1 - 0.21) - @bar_code_box_width | |
@page_infos.each_with_index do |info, i| | |
p = i + 1 | |
y = info[:center_box_top] | |
@layout.pdf.go_to_page(p) | |
h1 = @layout.text_box("DANFE", :style => :bold, :size => 12, :at => [center_info_left, y], | |
:width => MAX_WIDTH * 0.2, :align => :center) | |
h2 = @layout.text_box("DOCUMENTO AUXILIAR DA NOTA FISCAL ELETRÔNICA", :size => 8, | |
:at => [center_info_left, y - (h1 + 6)], :width => MAX_WIDTH * 0.2, | |
:align => :center) | |
hs = h1 + 6 + h2 + 6 | |
[['TIPO:', 'ENTRADA'], ['Nº:', @data[:numero]], ['SÉRIE:', @data[:serie]], ['FOLHA:', "#{p}/#{@layout.pdf.page_count}"]].each do |x| | |
hi = @layout.text_box(x[0], :size => 10, | |
:at => [center_info_left, y - hs], :width => MAX_WIDTH * 0.08, | |
:align => :right) | |
@layout.text_box(x[1], :style => :bold, :size => 10, | |
:at => [center_info_left + MAX_WIDTH * 0.09, y - hs], | |
:width => MAX_WIDTH * 0.11, :align => :left) | |
hs += hi + 2 | |
end | |
end | |
end | |
def draw | |
@layout.pdf.stroke do | |
txt = "Recebemos de #{@data[:nome_emitente]} os produtos e/ou serviços constantes "\ | |
"na Nota Fiscal Eletrônica indicada ao lado." | |
@layout.pdf.text_box(txt, :size => 8, :at => [MAX_WIDTH * 0.02, @layout.y], | |
:width => MAX_WIDTH * (0.8 - 0.04 - 0.02), :valign => :top) | |
@layout.receipt_box('DATA DE RECEBIMENTO', @data[:data_entrada_saida] || @data[:data_emissao], 0.02, 0.20) | |
@layout.receipt_box('IDENTIFICAÇÃO E ASSINATURA DO RECEBEDOR', '', 0.24, 0.76) | |
@layout.pdf.text_box("NF-e", :style => :bold, :size => 10, :at => [MAX_WIDTH * 0.8, @layout.y], | |
:width => MAX_WIDTH * 0.2, :align => :center) | |
@layout.pdf.text_box("Nº #{@data[:numero]}\nSÉRIE #{@data[:serie]}", :size => 10, :at => [MAX_WIDTH * 0.8, @layout.y - 16], | |
:width => MAX_WIDTH * 0.2, :align => :center) | |
@layout.pdf.vertical_line(@layout.y, @layout.y - 44, :at => MAX_WIDTH * 0.8) | |
end | |
@layout.pdf.dash(2) | |
@layout.pdf.stroke do | |
@layout.pdf.horizontal_line(0, MAX_WIDTH, :at => @layout.y - 44) | |
end | |
@layout.pdf.undash | |
@layout.move_down(44 + SECTION_SPACING) | |
draw_header | |
@layout.section('DESTINATÁRIO/REMETENTE') do | |
@layout.row do |r| | |
r.text_box_with_box(65, 'NOME/RAZÃO SOCIAL', @data[:nome_destinatario]) | |
r.text_box_with_box(20, 'CNPJ/CPF', @data[:cnpj_destinatario]) | |
r.space(1) | |
r.text_box_with_box(:max, 'DATA DE EMISSÃO', @data[:data_emissao]) | |
end | |
@layout.row do |r| | |
r.text_box_with_box(50, 'ENDEREÇO', @data[:logradouro_destinatario]) | |
r.text_box_with_box(25, 'BAIRRO/DISTRITO', @data[:bairro_destinatario]) | |
r.text_box_with_box(10, 'CEP', @data[:cep_destinatario]) | |
r.space(1) | |
r.text_box_with_box(:max, 'DATA DE SAÍDA', @data[:data_entrada_saida]) | |
end | |
@layout.row do |r| | |
r.text_box_with_box(45, 'MUNICÍPIO', @data[:municipio_destinatario]) | |
r.text_box_with_box(18, 'FONE/FAX', @data[:telefone_destinatario]) | |
r.text_box_with_box(7, 'UF', @data[:uf_destinatario]) | |
r.text_box_with_box(15, 'INSCRIÇÃO ESTADUAL', @data[:inscricao_estadual_destinatario]) | |
r.space(1) | |
r.text_box_with_box(:max, 'HORA DE SAÍDA', @data[:hora_entrada_saida]) | |
end | |
end | |
unless @data[:duplicatas].empty? | |
@layout.section('FATURA/DUPLICATA') do | |
duplicatas = @data[:duplicatas].map { |x| [x[:numero], x[:data_vencimento], x[:valor]] } | |
@layout.table( | |
['NÚMERO', 'VENCIMENTO', 'VALOR'] * 3, | |
columnize_array(duplicatas, 3), | |
[11.11, 11.11, 11.11, 11.11, 11.11, 11.11, 11.11, 11.11, 11.12], | |
[:center, :center, :right, :center, :center, :right, :center, :center, :right], | |
:size => LABEL_SIZE) | |
end | |
end | |
@layout.section('CÁLCULO DE IMPOSTO') do | |
@layout.row do |r| | |
r.text_box_with_box(20, 'BASE DE CÁLCULO DO ICMS', @data[:icms_base_calculo]) | |
r.text_box_with_box(20, 'VALOR DO ICMS', @data[:icms_valor_total]) | |
r.text_box_with_box(20, 'BASE DE CÁLCULO DO ICMS ST', @data[:icms_base_calculo_st]) | |
r.text_box_with_box(20, 'VALOR DO ICMS ST', @data[:icms_valor_total_st]) | |
r.text_box_with_box(:max, 'VALOR TOTAL DOS PRODUTOS', @data[:valor_produtos]) | |
end | |
@layout.row do |r| | |
r.text_box_with_box(16, 'VALOR DO FRETE', @data[:valor_frete]) | |
r.text_box_with_box(16, 'VALOR DO SEGURO', @data[:valor_seguro]) | |
r.text_box_with_box(16, 'DESCONTO', @data[:valor_desconto]) | |
r.text_box_with_box(16, 'OUTRAS DESPESAS', @data[:valor_outras_despesas]) | |
r.text_box_with_box(16, 'VALOR DO IPI', @data[:valor_ipi]) | |
r.text_box_with_box(:max, 'VALOR TOTAL DA NOTA', @data[:valor_total]) | |
end | |
end | |
@layout.section('TRANSPORTADOR') do | |
@layout.row do |r| | |
r.text_box_with_box(30, 'NOME/RAZÃO SOCIAL', @data[:nome_transportador]) | |
r.text_box_with_box(15, 'FRETE POR CONTA', @data[:modalidade_frete]) | |
r.text_box_with_box(15, 'CÓDIGO ANTT', @data[:veiculo_rntc]) | |
r.text_box_with_box(15, 'PLACA DO VEÍCULO', @data[:veiculo_placa]) | |
r.text_box_with_box(7, 'UF', @data[:veiculo_uf]) | |
r.text_box_with_box(:max, 'CNPJ/CPF', @data[:cnpj_transportador]) | |
end | |
@layout.row do |r| | |
r.text_box_with_box(40, 'ENDEREÇO', @data[:endereco_transportador]) | |
r.text_box_with_box(35, 'MUNICÍPIO', @data[:municipio_transportador]) | |
r.text_box_with_box(7, 'UF', @data[:uf_transportador]) | |
r.text_box_with_box(:max, 'INSCRIÇÃO ESTADUAL', @data[:inscricao_estadual_transportador]) | |
end | |
end | |
@layout.section('VOLUMES TRANSPORTADOS') do | |
volumes = @data[:volumes].map { |x| [x[:quantidade], x[:especie], x[:marca], x[:numero], | |
x[:peso_liquido], x[:peso_bruto], nil] } | |
@layout.table( | |
['QUANTIDADE', 'ESPÉCIE', 'MARCA', 'NUMERAÇÃO', 'PESO BRUTO', 'PESO LÍQUIDO', ''], | |
volumes, | |
[11.11, 11.11, 11.11, 11.11, 11.11, 11.11, 33.34], | |
[:right, :left, :left, :left, :right, :right], | |
:size => LABEL_SIZE) | |
end | |
#icms_w = (@layout.pdf.width_of('15,00', :size => 8) + 2) / MAX_WIDTH * 100 | |
#ipi_w = (@layout.pdf.width_of('15,00', :size => 8) + 2) / MAX_WIDTH * 100 | |
reservado_ao_fisco_width = 212 | |
reservado_ao_fisco_height = 84 | |
table_data = @data[:itens].map { |x| [x[:codigo_produto], x[:descricao], x[:codigo_ncm], | |
x[:icms_item_situacao_tributaria], x[:cfop], x[:unidade_comercial], | |
x[:quantidade_comercial], x[:valor_unitario_comercial], x[:valor_bruto], | |
x[:icms_item_base_calculo], x[:icms_item_valor], x[:ipi_item_valor], | |
x[:icms_item_aliquota], x[:ipi_item_aliquota]] } | |
@layout.section('DADOS DOS PRODUTOS/SERVIÇOS') do | |
@layout.table( | |
['CÓD. PROD.', 'DESCRIÇÃO', 'NCM/SH', 'CST', 'CFOP', 'UNID.', 'QUANT.', 'VALOR UNIT.', | |
'VALOR TOTAL', 'BC ICMS', 'VALOR ICMS', 'VALOR IPI', 'ALÍQ. ICMS', 'ALÍQ. IPI'], | |
table_data, | |
[5, 28, 7, 4, 4, 5, 7, 7, 7, 7, 4, 7, 4, 4], | |
[:left, :left, :left, :left, :left, :left, :right, | |
:right, :right, :right, :right, :right, :right, :right], | |
{ :size => LABEL_SIZE }, | |
{ :heigth_calc => 1, :min_y => reservado_ao_fisco_height + SECTION_SPACING + @fs_warning_height }) | |
end | |
@layout.section('DADOS ADICIONAIS', :at => reservado_ao_fisco_height + SECTION_SPACING + @fs_warning_height) do | |
@layout.pdf.stroke do | |
@layout.text_box_with_box('INFORMAÇÕES ADICIONAIS', @data[:informacoes_adicionais_contribuinte], | |
MAX_WIDTH - reservado_ao_fisco_width, reservado_ao_fisco_height, :size => LABEL_SIZE) | |
@layout.text_box_with_box('RESERVADO AO FISCO', '', | |
reservado_ao_fisco_width, reservado_ao_fisco_height) | |
end | |
end | |
@layout.pdf.text_box("DANFE impresso em contingência devido a problemas técnicos", | |
:style => :bold, :size => 12, :at => [0, @fs_warning_height], :width => MAX_WIDTH, :valign => :bottom, | |
:align => :center) | |
while !table_data.empty? | |
@layout.start_new_page | |
draw_header | |
@layout.section('DADOS DOS PRODUTOS/SERVIÇOS') do | |
@layout.table( | |
['CÓD. PROD.', 'DESCRIÇÃO', 'NCM/SH', 'CST', 'CFOP', 'UNID.', 'QUANT.', 'VALOR UNIT.', | |
'VALOR TOTAL', 'BC ICMS', 'VALOR ICMS', 'VALOR IPI', 'ALÍQ. ICMS', 'ALÍQ. IPI'], | |
table_data, | |
[5, 28, 7, 4, 4, 5, 7, 7, 7, 7, 4, 7, 4, 4], | |
[:left, :left, :left, :left, :left, :left, :right, | |
:right, :right, :right, :right, :right, :right, :right], | |
{ :size => LABEL_SIZE }, | |
{ :heigth_calc => 1, :min_y => @fs_warning_height }) | |
end | |
@layout.pdf.text_box("DANFE impresso em contingência devido a problemas técnicos", | |
:style => :bold, :size => 12, :at => [0, @fs_warning_height], :width => MAX_WIDTH, :valign => :bottom, | |
:align => :center) | |
end | |
draw_center_info | |
@layout.write("prawn.pdf") | |
end | |
end | |
$informacoes_adicionais_contribuinte = <<EOS | |
I - "DOCUMENTO EMITIDO POR ME OU EPP OPTANTE PELO SIMPLES NACIONAL"; | |
II - "NÃO GERA DIREITO A CRÉDITO FISCAL DE ICMS, DE ISS E DE IPI". | |
ASM-8948 ASM-8994 ASM-8995 ASM-8996 ASM-9112 ASM-9128 ASM-9129 ASM-9130 ASM-9131 ASM-9132 ASM-9133 ASM-9134 ASM-9135 ASM-9136 ASM-9087 ASM-9093 ASM-9097 ASM-9102 ASM-9103 ASM-9104 ASM-9105 ASM-9106 ASM-9107 ASM-9108 ASM-9075 ASM-9076 ASM-9078 ASM-9079 ASM-9081 ASM-9082 ASM-9083 ASM-9084 ASM-9085 ASM-9086 ASM-9062 ASM-9065 ASM-9066 ASM-9067 ASM-9068 ASM-9069 ASM-9071 ASM-9072 ASM-9073 ASM-9074 ASM-9044 ASM-9045 ASM-9046 ASM-9047 ASM-9048 ASM-9049 ASM-9054 ASM-9055 ASM-9057 ASM-9061 ASM-9028 ASM-9029 ASM-9031 ASM-9032 ASM-9034 ASM-9035 ASM-9039 ASM-9040 ASM-9041 ASM-9043 ASM-9015 ASM-9016 ASM-9017 ASM-9018 ASM-9019 ASM-9021 ASM-9024 ASM-9025 ASM-9026 ASM-9027 ASM-9027 ASM-8904 ASM-8939 ASM-8940 ASM-8941 ASM-8942 ASM-8943 ASM-8944 ASM-8945 ASM-8946 ASM-8947 ASM-8795 ASM-8879 ASM-8891 ASM-8892 ASM-8893 ASM-8895 ASM-8897 ASM-8901 ASM-8902 ASM-8903 ASM-8779 ASM-8781 ASM-8782 ASM-8784 ASM-8785 ASM-8786 ASM-8789 ASM-8792 ASM-8793 ASM-8794 ASM-9137 ASM-8766 ASM-8769 ASM-8770 ASM-8771 ASM-8772 ASM-8773 ASM-8774 ASM-8775 ASM-8776 | |
EOS | |
$campos = { | |
:nome_logo => 'logo_adega_sul.png', | |
:chave_nfe => '41110504505771000191550010000004161391758308', | |
:ambiente => '2', | |
:chave_nfe_formatada => '4111 0504 5057 7100 0191 5500 1000 0004 1613 9175 8308', | |
#:formulario_seguranca => '0', | |
#:titulo_dados_nfe => 'PROTOCOLO DE AUTORIZAÇÃO DE USO', | |
#:conteudo_dados_nfe => '11090123456789 10/01/2011 10:00:00', | |
:formulario_seguranca => '1', | |
:titulo_dados_nfe => 'DADOS DA NF-E', | |
:conteudo_dados_nfe => '412030889240001800000000004540012257', | |
:forma_emissao => '1', | |
:numero => '10200', | |
:serie => '900', | |
:nome_emitente => 'Reciclamix Tamandaré Comércio de Materiais Recicláveis Ltda.', | |
:dados_emitente => "R. Justo Manfron, 1620 - Lamenha\nPequena - Almirante Tamandaré - PR\nCEP: 83.508-185 - Tel.: (41) 3272-1013", | |
:cnpj_emitente => '10.364.208/0001-43', | |
:inscricao_estadual_emitente => '9050417546', | |
:inscricao_estadual_st_emitente => '', | |
:informacoes_adicionais_contribuinte => $informacoes_adicionais_contribuinte, | |
:natureza_operacao => 'Venda', | |
:tipo_documento => '1', | |
:data_emissao => '10/01/2011', | |
:data_entrada_saida => '10/01/2011', | |
:hora_entrada_saida => '0:00:00', | |
:nome_destinatario => 'ANTONIO GENESIO CHAVES PEREIRA', | |
:cnpj_destinatario => '09.147.813/0001-83', | |
:inscricao_estadual_destinatario => '271259213', | |
:logradouro_destinatario => 'RUA BAHIA, 60 A', | |
:bairro_destinatario => '18 DO FORTE', | |
:municipio_destinatario => 'Aracaju', | |
:uf_destinatario => 'SE', | |
:cep_destinatario => '49.072-050', | |
:telefone_destinatario => '', | |
:valor_produtos => '907,83', | |
:valor_desconto => '0,01', | |
:valor_total => '907,82', | |
:icms_base_calculo => '907,83', | |
:icms_valor_total => '63,55', | |
:icms_base_calculo_st => '0,00', | |
:icms_valor_total_st => '0,00', | |
:valor_ipi => '0,00', | |
:valor_outras_despesas => '0,00', | |
:valor_frete => '0,00', | |
:valor_seguro => '0,00', | |
:modalidade_frete => 'Do destinatário', | |
:nome_transportador => '', | |
:cnpj_transportador => '', | |
:inscricao_estadual_transportador => '', | |
:endereco_transportador => '', | |
:municipio_transportador => '', | |
:uf_transportador => '', | |
:veiculo_placa => '', | |
:veiculo_uf => '', | |
:veiculo_rntc => '', | |
:numero_protocolo => '11090123456789', | |
:duplicatas => [ | |
{ | |
:numero => '000070-1', | |
:data_vencimento => '18/03/2010', | |
:valor => '961,50' | |
}, | |
{ | |
:numero => '000070-2', | |
:data_vencimento => '18/03/2010', | |
:valor => '961,50' | |
}, | |
{ | |
:numero => '000070-3', | |
:data_vencimento => '18/03/2010', | |
:valor => '961,50' | |
}, | |
{ | |
:numero => '000070-4', | |
:data_vencimento => '17/01/2011', | |
:valor => '978,32' | |
}, | |
{ | |
:numero => '000070-5', | |
:data_vencimento => '17/01/2011', | |
:valor => '978,32' | |
}, | |
{ | |
:numero => '000070-6', | |
:data_vencimento => '17/01/2011', | |
:valor => '978,32' | |
}, | |
{ | |
:numero => '000070-7', | |
:data_vencimento => '18/03/2010', | |
:valor => '978,30' | |
} | |
], | |
:volumes => [ | |
{ | |
:quantidade => '1', | |
:especie => 'CAIXA', | |
:marca => '', | |
:numero => '', | |
:peso_liquido => '', | |
:peso_bruto => '' | |
}, | |
{ | |
:quantidade => '4', | |
:especie => 'PACOTE', | |
:marca => '', | |
:numero => '', | |
:peso_liquido => '', | |
:peso_bruto => '' | |
} | |
], | |
:itens => [ | |
{ | |
:codigo_produto => 'TN05V', | |
:codigo_ncm => '39199000', | |
:valor_unitario_comercial => '2,5217', | |
:unidade_comercial => 'M', | |
:quantidade_comercial => '300,00', | |
:valor_bruto => '756,52', | |
:cfop => '6102', | |
:ipi_item_aliquota => '15,00', | |
:ipi_item_valor => '0,00', | |
:descricao => 'CARROCERIA ABERTA C/ 5,65M 5101 UN DE COMPR., COLOCADA EM M.BENZ 1620; CHASSI 9BM695014YB236958; PLACA MBY-5669', | |
:icms_item_situacao_tributaria => '100', | |
:icms_item_base_calculo => '756,52', | |
:icms_item_aliquota => '7,00', | |
:icms_item_valor => '52,96' | |
} | |
] | |
} | |
m = Benchmark.measure do | |
danfe = Danfe.new($campos) | |
danfe.draw | |
end | |
puts m | |
`cmd /c start prawn.pdf` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment