facturae_print 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +21 -0
- data/Rakefile +6 -0
- data/bin/facturae_print +8 -0
- data/facturae_print.gemspec +27 -0
- data/lib/facturae_print.rb +6 -0
- data/lib/facturae_print/cli.rb +42 -0
- data/lib/facturae_print/core_ext/string.rb +15 -0
- data/lib/facturae_print/invoice.rb +19 -0
- data/lib/facturae_print/renderers/html_renderer.rb +24 -0
- data/lib/facturae_print/renderers/html_renderer_helpers.rb +25 -0
- data/lib/facturae_print/renderers/pdf_renderer.rb +33 -0
- data/lib/facturae_print/version.rb +3 -0
- data/lib/facturae_print/xml_objectifier.rb +34 -0
- data/spec/fixtures/facturae.xml +144 -0
- data/spec/invoice_spec.rb +28 -0
- data/spec/renderers/html_renderer_spec.rb +19 -0
- data/spec/renderers/pdf_renderer_spec.rb +55 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/xml_objectifier_spec.rb +108 -0
- data/templates/default.css +127 -0
- data/templates/default.eruby +86 -0
- metadata +192 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Álvaro Bautista
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# FacturaePrint
|
2
|
+
|
3
|
+
FacturaePrint translates a facturae xml file into an understandable HTML or PDF file.
|
4
|
+
|
5
|
+
The facturae format specification is available on [http://www.facturae.es](http://www.facturae.es). There is also an english version available [here](http://www.facturae.es/es-ES/Documentacion/EsquemaFormato/Esquema%20Formato/Versi%C3%B3n%203_2/Esquema_ingles_v3_2.pdf).
|
6
|
+
|
7
|
+
### Installation
|
8
|
+
|
9
|
+
gem install facturae_print
|
10
|
+
|
11
|
+
### Usage
|
12
|
+
|
13
|
+
FacturaePrint uses [erubis](http://www.kuwata-lab.com/erubis) to translate the facturae xml file into an html file. It also can generate a pdf version from the generated html file, using [PDFKit](http://github.com/jdpace/PDFKit). Nothing fancy.
|
14
|
+
|
15
|
+
Right. Let's see some examples:
|
16
|
+
|
17
|
+
facturae_print html 022011.xml templates/default.eruby -o test.html
|
18
|
+
|
19
|
+
facturae_print pdf 022011.xml templates/default.eruby -s templates/default.css -o test.pdf
|
20
|
+
|
21
|
+
That's it. What else did you expect?
|
data/Rakefile
ADDED
data/bin/facturae_print
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "facturae_print/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "facturae_print"
|
7
|
+
s.version = FacturaePrint::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Alvaro Bautista"]
|
10
|
+
s.email = ["alvarobp@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{facturae_print translates a facturae xml file into an understandable HTML or PDF file}
|
13
|
+
s.description = %q{facturae_print translates a facturae xml file into an understandable HTML or PDF file}
|
14
|
+
|
15
|
+
s.add_dependency("nokogiri", ">= 1.4.4")
|
16
|
+
s.add_dependency("erubis", ">= 2.6.6")
|
17
|
+
s.add_dependency("wkhtmltopdf-binary", ">= 0.9.5.1")
|
18
|
+
s.add_dependency("pdfkit", ">= 0.5.0")
|
19
|
+
s.add_dependency("thor", ">= 0.14.6")
|
20
|
+
|
21
|
+
s.add_development_dependency("rspec", "~> 2.4.0")
|
22
|
+
|
23
|
+
s.files = `git ls-files`.split("\n")
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
require 'facturae_print/xml_objectifier'
|
2
|
+
require 'facturae_print/invoice'
|
3
|
+
require 'facturae_print/renderers/html_renderer_helpers'
|
4
|
+
require 'facturae_print/renderers/html_renderer'
|
5
|
+
require 'facturae_print/renderers/pdf_renderer'
|
6
|
+
require 'facturae_print/core_ext/string'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module FacturaePrint
|
4
|
+
class CLI < Thor
|
5
|
+
|
6
|
+
desc "html facturae_xml eruby_template", "Generates an html version for a facturae xml"
|
7
|
+
method_option :output, :type => :string, :aliases => "-o", :banner => "Output to a file instead of into stdio"
|
8
|
+
def html(facturae_xml, eruby_template)
|
9
|
+
invoice = FacturaePrint::Invoice.new(File.read(facturae_xml))
|
10
|
+
template = File.read(eruby_template)
|
11
|
+
|
12
|
+
html_renderer = FacturaePrint::Renderers::HTMLRenderer.new(template, invoice)
|
13
|
+
rendered_html = html_renderer.render
|
14
|
+
|
15
|
+
if options[:output]
|
16
|
+
File.open(options[:output], 'w') { |f| f.write(rendered_html) }
|
17
|
+
else
|
18
|
+
shell.say(rendered_html)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "pdf facturae_xml eruby_template", "Generates a pdf version for a facturae xml"
|
23
|
+
method_option :stylesheet, :type => :string, :aliases => "-s", :banner => "Use the given CSS stylesheet on rendering"
|
24
|
+
method_option :output, :type => :string, :aliases => "-o", :banner => "Output to a file instead of into stdio"
|
25
|
+
def pdf(facturae_xml, eruby_template)
|
26
|
+
invoice = FacturaePrint::Invoice.new(File.read(facturae_xml))
|
27
|
+
template = File.read(eruby_template)
|
28
|
+
renderer_options = {}
|
29
|
+
renderer_options[:stylesheet] = File.read(options[:stylesheet]) if options[:stylesheet]
|
30
|
+
|
31
|
+
pdf_renderer = FacturaePrint::Renderers::PDFRenderer.new(template, invoice, renderer_options)
|
32
|
+
rendered_pdf = pdf_renderer.render
|
33
|
+
|
34
|
+
if options[:output]
|
35
|
+
File.open(options[:output], 'w') { |f| f.write(rendered_pdf) }
|
36
|
+
else
|
37
|
+
shell.say(rendered_pdf)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
unless method_defined?(:underscore)
|
4
|
+
define_method :underscore do
|
5
|
+
word = self.dup
|
6
|
+
word.gsub!(/::/, '/')
|
7
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
8
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
9
|
+
word.tr!("-", "_")
|
10
|
+
word.downcase!
|
11
|
+
word
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module FacturaePrint
|
5
|
+
|
6
|
+
class Invoice < OpenStruct
|
7
|
+
|
8
|
+
def initialize(xml_file)
|
9
|
+
super(nil)
|
10
|
+
xml = Nokogiri::XML(xml_file)
|
11
|
+
|
12
|
+
FacturaePrint::XMLObjectifier.build(xml.root,
|
13
|
+
:object => self,
|
14
|
+
:collection_nodes => ["Invoices", "TaxesOutputs", "Items"])
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
module FacturaePrint
|
4
|
+
module Renderers
|
5
|
+
class HTMLRenderer
|
6
|
+
|
7
|
+
def initialize(template, invoice)
|
8
|
+
@template = template
|
9
|
+
@invoice = invoice
|
10
|
+
end
|
11
|
+
|
12
|
+
def render
|
13
|
+
eruby = Erubis::Eruby.new(@template)
|
14
|
+
__context = Erubis::Context.new
|
15
|
+
class << __context
|
16
|
+
include FacturaePrint::Renderers::HTMLRendererHelpers
|
17
|
+
end
|
18
|
+
__context[:invoice] = @invoice
|
19
|
+
eruby.evaluate(__context)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module FacturaePrint
|
2
|
+
module Renderers
|
3
|
+
module HTMLRendererHelpers
|
4
|
+
|
5
|
+
def to_currency(amount)
|
6
|
+
@invoice_currency_symbol ||= currency_symbol(@invoice.invoices.first.invoice_issue_data.invoice_currency_code)
|
7
|
+
"#{amount} #{@invoice_currency_symbol}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def currency_symbol(currency_code)
|
11
|
+
case currency_code
|
12
|
+
when "EUR": "€"
|
13
|
+
when "USD": "$"
|
14
|
+
else
|
15
|
+
currency_code
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def individual_full_name(individual)
|
20
|
+
[individual.name, individual.first_surname, individual.second_surname].compact.join(' ')
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'pdfkit'
|
2
|
+
|
3
|
+
module FacturaePrint
|
4
|
+
module Renderers
|
5
|
+
class PDFRenderer
|
6
|
+
|
7
|
+
def initialize(template, invoice, args={})
|
8
|
+
@template = template
|
9
|
+
@invoice = invoice
|
10
|
+
@stylesheet = args.delete(:stylesheet)
|
11
|
+
@pdfkit_options = args
|
12
|
+
end
|
13
|
+
|
14
|
+
def render
|
15
|
+
html = FacturaePrint::Renderers::HTMLRenderer.new(@template, @invoice).render
|
16
|
+
|
17
|
+
append_stylesheet_tag(html, (@stylesheet.is_a?(IO) ? @stylesheet.read : @stylesheet)) if @stylesheet
|
18
|
+
PDFKit.new(html, @pdfkit_options).to_pdf
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def append_stylesheet_tag(html_string, stylesheet)
|
24
|
+
if html_string.match(/<\/head>/)
|
25
|
+
html_string.gsub!(/(<\/head>)/, "<style>#{stylesheet}</style>"+'\1')
|
26
|
+
else
|
27
|
+
html_string.insert(0, "<style>#{stylesheet}</style>")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module FacturaePrint
|
2
|
+
module XMLObjectifier
|
3
|
+
|
4
|
+
def self.build(node, options={})
|
5
|
+
options = {:collection_nodes => []}.merge(options)
|
6
|
+
return node.text if node.text?
|
7
|
+
|
8
|
+
children = get_node_children(node)
|
9
|
+
return nil if children.empty? && node.content.empty?
|
10
|
+
|
11
|
+
if children.size == 1 && children.first.text?
|
12
|
+
children.first.text
|
13
|
+
else
|
14
|
+
object = options.delete(:object) || OpenStruct.new
|
15
|
+
children.each do |child|
|
16
|
+
value = if options[:collection_nodes].include?(child.name)
|
17
|
+
get_node_children(child).map{|c| build(c, options)}
|
18
|
+
else
|
19
|
+
build(child, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
object.send("#{child.name.underscore}=", value)
|
23
|
+
end
|
24
|
+
object
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def self.get_node_children(node)
|
31
|
+
node.children.reject { |c| c.blank? }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<fe:Facturae xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:fe="http://www.facturae.es/Facturae/2007/v3.1/Facturae">
|
3
|
+
<FileHeader>
|
4
|
+
<SchemaVersion>3.1</SchemaVersion>
|
5
|
+
<Modality>I</Modality>
|
6
|
+
<InvoiceIssuerType>RE</InvoiceIssuerType>
|
7
|
+
<Batch>
|
8
|
+
<BatchIdentifier>12345678A</BatchIdentifier>
|
9
|
+
<InvoicesCount>1</InvoicesCount>
|
10
|
+
<TotalInvoicesAmount>
|
11
|
+
<TotalAmount>637.50</TotalAmount>
|
12
|
+
</TotalInvoicesAmount>
|
13
|
+
<TotalOutstandingAmount>
|
14
|
+
<TotalAmount>637.50</TotalAmount>
|
15
|
+
</TotalOutstandingAmount>
|
16
|
+
<TotalExecutableAmount>
|
17
|
+
<TotalAmount>637.50</TotalAmount>
|
18
|
+
</TotalExecutableAmount>
|
19
|
+
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
20
|
+
</Batch>
|
21
|
+
</FileHeader>
|
22
|
+
<Parties>
|
23
|
+
<SellerParty>
|
24
|
+
<TaxIdentification>
|
25
|
+
<PersonTypeCode>F</PersonTypeCode>
|
26
|
+
<ResidenceTypeCode>E</ResidenceTypeCode>
|
27
|
+
<TaxIdentificationNumber>12345678A</TaxIdentificationNumber>
|
28
|
+
</TaxIdentification>
|
29
|
+
<Individual>
|
30
|
+
<Name>John</Name>
|
31
|
+
<FirstSurname>Developer</FirstSurname>
|
32
|
+
<SecondSurname/>
|
33
|
+
<AddressInSpain>
|
34
|
+
<Address>Colón 14</Address>
|
35
|
+
<PostCode>28004</PostCode>
|
36
|
+
<Town>Madrid</Town>
|
37
|
+
<Province>Madrid</Province>
|
38
|
+
<CountryCode>ESP</CountryCode>
|
39
|
+
</AddressInSpain>
|
40
|
+
<ContactDetails>
|
41
|
+
<Telephone>98765432</Telephone>
|
42
|
+
<ElectronicMail>john@developer.com</ElectronicMail>
|
43
|
+
</ContactDetails>
|
44
|
+
</Individual>
|
45
|
+
</SellerParty>
|
46
|
+
<BuyerParty>
|
47
|
+
<TaxIdentification>
|
48
|
+
<PersonTypeCode>J</PersonTypeCode>
|
49
|
+
<ResidenceTypeCode>E</ResidenceTypeCode>
|
50
|
+
<TaxIdentificationNumber>Z12345678</TaxIdentificationNumber>
|
51
|
+
</TaxIdentification>
|
52
|
+
<LegalEntity>
|
53
|
+
<CorporateName>Biggest Company</CorporateName>
|
54
|
+
<AddressInSpain>
|
55
|
+
<Address>Gran Vía 28</Address>
|
56
|
+
<PostCode>28013</PostCode>
|
57
|
+
<Town>Madrid</Town>
|
58
|
+
<Province>Madrid</Province>
|
59
|
+
<CountryCode>ESP</CountryCode>
|
60
|
+
</AddressInSpain>
|
61
|
+
<ContactDetails>
|
62
|
+
<Telephone>654321987</Telephone>
|
63
|
+
<ElectronicMail>biggest@company.es</ElectronicMail>
|
64
|
+
</ContactDetails>
|
65
|
+
</LegalEntity>
|
66
|
+
</BuyerParty>
|
67
|
+
</Parties>
|
68
|
+
<Invoices>
|
69
|
+
<Invoice>
|
70
|
+
<InvoiceHeader>
|
71
|
+
<InvoiceNumber>1</InvoiceNumber>
|
72
|
+
<InvoiceDocumentType>FC</InvoiceDocumentType>
|
73
|
+
<InvoiceClass>OO</InvoiceClass>
|
74
|
+
</InvoiceHeader>
|
75
|
+
<InvoiceIssueData>
|
76
|
+
<IssueDate>2011-01-31</IssueDate>
|
77
|
+
<InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>
|
78
|
+
<TaxCurrencyCode>EUR</TaxCurrencyCode>
|
79
|
+
<LanguageName>es</LanguageName>
|
80
|
+
</InvoiceIssueData>
|
81
|
+
<TaxesOutputs>
|
82
|
+
<Tax>
|
83
|
+
<TaxTypeCode>04</TaxTypeCode>
|
84
|
+
<TaxRate>-15.00</TaxRate>
|
85
|
+
<TaxableBase>
|
86
|
+
<TotalAmount>750.00</TotalAmount>
|
87
|
+
</TaxableBase>
|
88
|
+
<TaxAmount>
|
89
|
+
<TotalAmount>-112.50</TotalAmount>
|
90
|
+
</TaxAmount>
|
91
|
+
</Tax>
|
92
|
+
</TaxesOutputs>
|
93
|
+
<InvoiceTotals>
|
94
|
+
<TotalGrossAmount>750.00</TotalGrossAmount>
|
95
|
+
<TotalGrossAmountBeforeTaxes>750.00</TotalGrossAmountBeforeTaxes>
|
96
|
+
<TotalTaxOutputs>-112.50</TotalTaxOutputs>
|
97
|
+
<TotalTaxesWithheld>0.00</TotalTaxesWithheld>
|
98
|
+
<InvoiceTotal>637.50</InvoiceTotal>
|
99
|
+
<TotalOutstandingAmount>637.50</TotalOutstandingAmount>
|
100
|
+
<TotalExecutableAmount>637.50</TotalExecutableAmount>
|
101
|
+
</InvoiceTotals>
|
102
|
+
<Items>
|
103
|
+
<InvoiceLine>
|
104
|
+
<ItemDescription>Working too hard</ItemDescription>
|
105
|
+
<Quantity>1.00</Quantity>
|
106
|
+
<UnitPriceWithoutTax>700.000000</UnitPriceWithoutTax>
|
107
|
+
<TotalCost>700.00</TotalCost>
|
108
|
+
<GrossAmount>700.00</GrossAmount>
|
109
|
+
<TaxesOutputs>
|
110
|
+
<Tax>
|
111
|
+
<TaxTypeCode>04</TaxTypeCode>
|
112
|
+
<TaxRate>-15.00</TaxRate>
|
113
|
+
<TaxableBase>
|
114
|
+
<TotalAmount>700.00</TotalAmount>
|
115
|
+
</TaxableBase>
|
116
|
+
<TaxAmount>
|
117
|
+
<TotalAmount>-105.00</TotalAmount>
|
118
|
+
</TaxAmount>
|
119
|
+
</Tax>
|
120
|
+
</TaxesOutputs>
|
121
|
+
</InvoiceLine>
|
122
|
+
<InvoiceLine>
|
123
|
+
<ItemDescription>Working not as hard as before</ItemDescription>
|
124
|
+
<Quantity>1.00</Quantity>
|
125
|
+
<UnitPriceWithoutTax>50.000000</UnitPriceWithoutTax>
|
126
|
+
<TotalCost>50.00</TotalCost>
|
127
|
+
<GrossAmount>50.00</GrossAmount>
|
128
|
+
<TaxesOutputs>
|
129
|
+
<Tax>
|
130
|
+
<TaxTypeCode>04</TaxTypeCode>
|
131
|
+
<TaxRate>-15.00</TaxRate>
|
132
|
+
<TaxableBase>
|
133
|
+
<TotalAmount>50.00</TotalAmount>
|
134
|
+
</TaxableBase>
|
135
|
+
<TaxAmount>
|
136
|
+
<TotalAmount>-7.50</TotalAmount>
|
137
|
+
</TaxAmount>
|
138
|
+
</Tax>
|
139
|
+
</TaxesOutputs>
|
140
|
+
</InvoiceLine>
|
141
|
+
</Items>
|
142
|
+
</Invoice>
|
143
|
+
</Invoices>
|
144
|
+
</fe:Facturae>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe FacturaePrint::Invoice do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@invoice = FacturaePrint::Invoice.new(fixture('facturae.xml'))
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should instantiate as an OpenStruct mapping fe:Facturae node children" do
|
10
|
+
@invoice.file_header.schema_version = "3.1"
|
11
|
+
@invoice.file_header.batch.batch_identifier = "12345678A"
|
12
|
+
@invoice.parties.seller_party.individual.name.should == "John"
|
13
|
+
@invoice.parties.seller_party.individual.first_surname.should == "Developer"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should build the proper collections" do
|
17
|
+
# Collections: Invoices, TaxesOutputs, Items
|
18
|
+
@invoice.invoices.should be_a(Array)
|
19
|
+
@invoice.invoices.size.should == 1
|
20
|
+
@invoice.invoices.first.taxes_outputs.should be_a(Array)
|
21
|
+
@invoice.invoices.first.taxes_outputs.first.tax_rate.should == "-15.00"
|
22
|
+
@invoice.invoices.first.items.should be_a(Array)
|
23
|
+
@invoice.invoices.first.items.size.should == 2
|
24
|
+
@invoice.invoices.first.items[0].item_description = "Working too hard"
|
25
|
+
@invoice.invoices.first.items[1].item_description = "Working not as hard as before"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
2
|
+
|
3
|
+
describe FacturaePrint::Renderers::HTMLRenderer do
|
4
|
+
|
5
|
+
it "should render the given template with the given invoice object as @invoice instance variable" do
|
6
|
+
templ = "Example with <%= @invoice.name %>"
|
7
|
+
fake_invoice = OpenStruct.new("name" => "My first invoice ever")
|
8
|
+
html_renderer = FacturaePrint::Renderers::HTMLRenderer.new(templ, fake_invoice)
|
9
|
+
html_renderer.render.should == "Example with My first invoice ever"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should make FacturaePrint::Renderers::HTMLRendererHelpers methods available" do
|
13
|
+
templ = "Example with <%= @invoice.name %> for a value of 6000 <%= currency_code('USD') %>"
|
14
|
+
fake_invoice = OpenStruct.new("name" => "My first invoice ever")
|
15
|
+
html_renderer = FacturaePrint::Renderers::HTMLRenderer.new(templ, fake_invoice)
|
16
|
+
"Example with My first invoice ever for a value of 6000 $"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
2
|
+
|
3
|
+
describe FacturaePrint::Renderers::PDFRenderer do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@invoice = OpenStruct.new("name" => "My first invoice ever")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should render the given template using HTMLRenderer and use it to render with PDFKit" do
|
10
|
+
templ = "Example with <%= @invoice.name %>"
|
11
|
+
|
12
|
+
pdf_renderer = FacturaePrint::Renderers::PDFRenderer.new(templ, @invoice)
|
13
|
+
kit_mock = mock()
|
14
|
+
kit_mock.stub(:to_pdf).and_return("PDF RESULT")
|
15
|
+
|
16
|
+
PDFKit.should_receive(:new).with("Example with My first invoice ever", anything()).and_return(kit_mock)
|
17
|
+
pdf_renderer.render.should == "PDF RESULT"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should append stylesheet string passed in the stylesheet option" do
|
21
|
+
templ = "Example with <%= @invoice.name %>"
|
22
|
+
css = "* { border:1px solid red; }"
|
23
|
+
|
24
|
+
pdf_renderer = FacturaePrint::Renderers::PDFRenderer.new(templ, @invoice, :stylesheet => css)
|
25
|
+
kit_mock = mock()
|
26
|
+
kit_mock.stub(:to_pdf).and_return("PDF RESULT")
|
27
|
+
|
28
|
+
PDFKit.should_receive(:new).with("<style>#{css}</style>Example with My first invoice ever", anything()).and_return(kit_mock)
|
29
|
+
pdf_renderer.render.should == "PDF RESULT"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should append stylesheet string passed in the stylesheet option to the head section if there is one" do
|
33
|
+
templ = "<html><head><title>Invoice</title></head><body>Example with <%= @invoice.name %></body></html>"
|
34
|
+
css = "* { border:1px solid red; }"
|
35
|
+
|
36
|
+
pdf_renderer = FacturaePrint::Renderers::PDFRenderer.new(templ, @invoice, :stylesheet => css)
|
37
|
+
kit_mock = mock()
|
38
|
+
kit_mock.stub(:to_pdf).and_return("PDF RESULT")
|
39
|
+
|
40
|
+
PDFKit.should_receive(:new).with("<html><head><title>Invoice</title><style>#{css}</style></head><body>Example with My first invoice ever</body></html>", anything()).and_return(kit_mock)
|
41
|
+
pdf_renderer.render.should == "PDF RESULT"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should pass given options to PDFKit" do
|
45
|
+
templ = "Example with <%= @invoice.name %>"
|
46
|
+
|
47
|
+
pdf_renderer = FacturaePrint::Renderers::PDFRenderer.new(templ, @invoice, :page_size => "A4")
|
48
|
+
kit_mock = mock()
|
49
|
+
kit_mock.stub(:to_pdf).and_return("PDF RESULT")
|
50
|
+
|
51
|
+
PDFKit.should_receive(:new).with("Example with My first invoice ever", {:page_size => "A4"}).and_return(kit_mock)
|
52
|
+
pdf_renderer.render.should == "PDF RESULT"
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$:.unshift File.expand_path('..', __FILE__)
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'facturae_print'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
# == Mock Framework
|
9
|
+
#
|
10
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
11
|
+
#
|
12
|
+
# config.mock_with :mocha
|
13
|
+
# config.mock_with :flexmock
|
14
|
+
# config.mock_with :rr
|
15
|
+
config.mock_with :rspec
|
16
|
+
end
|
17
|
+
|
18
|
+
def fixture(name)
|
19
|
+
if @fixtures.nil?
|
20
|
+
@fixtures ||= {}
|
21
|
+
Dir["#{File.expand_path('../fixtures', __FILE__)}/*"].each do |file|
|
22
|
+
pathname = Pathname.new(file)
|
23
|
+
@fixtures[pathname.basename.to_s] = pathname.read
|
24
|
+
end
|
25
|
+
end
|
26
|
+
@fixtures[name]
|
27
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe FacturaePrint::XMLObjectifier do
|
4
|
+
|
5
|
+
it "should build from one node xml" do
|
6
|
+
xml = "<lonely>1</lonely>"
|
7
|
+
|
8
|
+
object = FacturaePrint::XMLObjectifier.build(Nokogiri::XML(xml))
|
9
|
+
object.should be_a(OpenStruct)
|
10
|
+
object.lonely.should == "1"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should build from xml with nested nodes" do
|
14
|
+
xml = <<-XML
|
15
|
+
<zoo>
|
16
|
+
<tiger>
|
17
|
+
<name>Shere Khan</name>
|
18
|
+
</tiger>
|
19
|
+
<lion>
|
20
|
+
<name>Mufasa</name>
|
21
|
+
<dimensions>
|
22
|
+
<height>
|
23
|
+
<unit>inches</unit>
|
24
|
+
<value>30</value>
|
25
|
+
</height>
|
26
|
+
<length>
|
27
|
+
<unit>meters</unit>
|
28
|
+
<value>2</value>
|
29
|
+
</length>
|
30
|
+
</dimensions>
|
31
|
+
</lion>
|
32
|
+
</zoo>
|
33
|
+
XML
|
34
|
+
|
35
|
+
object = FacturaePrint::XMLObjectifier.build(Nokogiri::XML(xml).root)
|
36
|
+
object.tiger.name.should == "Shere Khan"
|
37
|
+
object.lion.name.should == "Mufasa"
|
38
|
+
object.lion.dimensions.height.unit.should == "inches"
|
39
|
+
object.lion.dimensions.height.value.should == "30"
|
40
|
+
object.lion.dimensions.length.unit.should == "meters"
|
41
|
+
object.lion.dimensions.length.value.should == "2"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should underscore node names" do
|
45
|
+
xml = "<Person><PersonName>Ronald</PersonName></Person>"
|
46
|
+
object = FacturaePrint::XMLObjectifier.build(Nokogiri::XML(xml))
|
47
|
+
object.person.person_name.should == "Ronald"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should ignore empty nodes" do
|
51
|
+
xml = "<Person><PersonName>Ronald</PersonName><PersonSurname/></Person>"
|
52
|
+
object = FacturaePrint::XMLObjectifier.build(Nokogiri::XML(xml))
|
53
|
+
object.person.person_name.should == "Ronald"
|
54
|
+
object.person.person_surname.should be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should build on a given object" do
|
58
|
+
xml = "<arm><wrist>2</wrist><hand>3</hand></arm>"
|
59
|
+
object = OpenStruct.new({"elbow" => "1"})
|
60
|
+
|
61
|
+
FacturaePrint::XMLObjectifier.build(Nokogiri::XML(xml).root, :object => object)
|
62
|
+
object.elbow.should == "1"
|
63
|
+
object.wrist.should == "2"
|
64
|
+
object.hand.should == "3"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should build array for nodes with name in collection_nodes option" do
|
68
|
+
xml = <<-XML
|
69
|
+
<agenda>
|
70
|
+
<size>3</size>
|
71
|
+
<contacts>
|
72
|
+
<contact>
|
73
|
+
<name>Muddy Waters</name>
|
74
|
+
<numbers>
|
75
|
+
<number>555-1234</number>
|
76
|
+
<number>555-2341</number>
|
77
|
+
</numbers>
|
78
|
+
</contact>
|
79
|
+
<contact>
|
80
|
+
<name>Keith Richards</name>
|
81
|
+
<numbers>
|
82
|
+
<number>555-5678</number>
|
83
|
+
</numbers>
|
84
|
+
</contact>
|
85
|
+
<contact>
|
86
|
+
<name>Steve Marriott</name>
|
87
|
+
</contact>
|
88
|
+
</contacts>
|
89
|
+
</agenda>
|
90
|
+
XML
|
91
|
+
|
92
|
+
object = FacturaePrint::XMLObjectifier.build(Nokogiri::XML(xml).root, :collection_nodes => ["contacts", "numbers"])
|
93
|
+
object.size.should == "3"
|
94
|
+
object.contacts.should be_a(Array)
|
95
|
+
object.contacts[0].name.should == "Muddy Waters"
|
96
|
+
object.contacts[0].numbers.should be_a(Array)
|
97
|
+
object.contacts[0].numbers.size.should == 2
|
98
|
+
object.contacts[0].numbers[0].should == "555-1234"
|
99
|
+
object.contacts[0].numbers[1].should == "555-2341"
|
100
|
+
object.contacts[1].name.should == "Keith Richards"
|
101
|
+
object.contacts[1].numbers.should be_a(Array)
|
102
|
+
object.contacts[1].numbers.size.should == 1
|
103
|
+
object.contacts[1].numbers[0].should == "555-5678"
|
104
|
+
object.contacts[2].name.should == "Steve Marriott"
|
105
|
+
object.contacts[2].numbers.should be_nil
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
body {
|
2
|
+
font-family: Helvetica, Arial, sans-serif;
|
3
|
+
font-size: 14px;
|
4
|
+
}
|
5
|
+
|
6
|
+
.wrapper {
|
7
|
+
position: relative;
|
8
|
+
overflow: hidden;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1 {
|
12
|
+
margin: 0;
|
13
|
+
padding: 0;
|
14
|
+
}
|
15
|
+
|
16
|
+
dl {
|
17
|
+
margin: 0;
|
18
|
+
overflow: hidden;
|
19
|
+
}
|
20
|
+
|
21
|
+
.header {
|
22
|
+
position: absolute;
|
23
|
+
top: 0;
|
24
|
+
right: 0;
|
25
|
+
}
|
26
|
+
|
27
|
+
.header h1 {
|
28
|
+
margin-top: -5px;
|
29
|
+
font-size: 35px;
|
30
|
+
color: #666;
|
31
|
+
}
|
32
|
+
|
33
|
+
.seller-data .name,
|
34
|
+
.buyer-data .name {
|
35
|
+
font-size: 1.2em;
|
36
|
+
padding-bottom: 5px;
|
37
|
+
}
|
38
|
+
|
39
|
+
.seller-data p,
|
40
|
+
.buyer-data p {
|
41
|
+
margin: 0;
|
42
|
+
}
|
43
|
+
|
44
|
+
.invoice-header-data dl dt,
|
45
|
+
.invoice-header-data dl dd,
|
46
|
+
.buyer-data dt,
|
47
|
+
.buyer-data dd {
|
48
|
+
float: left;
|
49
|
+
margin: 0;
|
50
|
+
padding-bottom: 5px;
|
51
|
+
}
|
52
|
+
|
53
|
+
.invoice-header-data dl dt,
|
54
|
+
.buyer-data dl dt {
|
55
|
+
clear: left;
|
56
|
+
width: 150px;
|
57
|
+
font-weight: bold;
|
58
|
+
}
|
59
|
+
|
60
|
+
.invoice-header-data {
|
61
|
+
overflow: hidden;
|
62
|
+
margin: 30px 0 25px 0;
|
63
|
+
}
|
64
|
+
|
65
|
+
.buyer-data {
|
66
|
+
padding-bottom: 40px;
|
67
|
+
}
|
68
|
+
|
69
|
+
.invoice-details {
|
70
|
+
width: 100%;
|
71
|
+
border-collapse:collapse;
|
72
|
+
border-bottom: 1px solid #000;
|
73
|
+
}
|
74
|
+
|
75
|
+
.invoice-details .col1 {
|
76
|
+
width: 80%;
|
77
|
+
}
|
78
|
+
|
79
|
+
.invoice-details .col2 {
|
80
|
+
width: 20%
|
81
|
+
}
|
82
|
+
|
83
|
+
.invoice-details th {
|
84
|
+
padding: 5px 0;
|
85
|
+
border: 1px solid #000;
|
86
|
+
}
|
87
|
+
|
88
|
+
.invoice-details td {
|
89
|
+
padding: 10px 20px;
|
90
|
+
}
|
91
|
+
|
92
|
+
.invoice-details .description {
|
93
|
+
border-left: 1px solid #000;
|
94
|
+
border-right: 1px solid #000;
|
95
|
+
}
|
96
|
+
|
97
|
+
.invoice-details .amount {
|
98
|
+
text-align: right;
|
99
|
+
border-right: 1px solid #000;
|
100
|
+
}
|
101
|
+
|
102
|
+
.invoice-details .invoice-subtotal td {
|
103
|
+
border-top: 1px solid #000;
|
104
|
+
}
|
105
|
+
|
106
|
+
.invoice-details .invoice-taxes td {
|
107
|
+
padding-top: 0px;
|
108
|
+
}
|
109
|
+
|
110
|
+
.invoice-details .invoice-subtotal .description,
|
111
|
+
.invoice-details .invoice-taxes .description,
|
112
|
+
.invoice-details .invoice-total .description {
|
113
|
+
text-align: right;
|
114
|
+
}
|
115
|
+
|
116
|
+
.invoice-details .invoice-taxes .description,
|
117
|
+
.invoice-details .invoice-total .description {
|
118
|
+
font-weight: bold;
|
119
|
+
}
|
120
|
+
|
121
|
+
.invoice-details .invoice-total td {
|
122
|
+
border-top: 1px solid #000;
|
123
|
+
}
|
124
|
+
|
125
|
+
.footer {
|
126
|
+
margin-top: 40px;
|
127
|
+
}
|
@@ -0,0 +1,86 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<link rel="stylesheet" type="text/css" href="./default.css" />
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<div class="wrapper">
|
9
|
+
<div class="header">
|
10
|
+
<h1>Factura</h1>
|
11
|
+
</div>
|
12
|
+
<div class="seller-data">
|
13
|
+
<p class="name"><%= individual_full_name(@invoice.parties.seller_party.individual) %></p>
|
14
|
+
<p><%= @invoice.parties.seller_party.individual.address_in_spain.address %></p>
|
15
|
+
<p><%= @invoice.parties.seller_party.individual.address_in_spain.post_code %> <%= @invoice.parties.seller_party.individual.address_in_spain.town %></p>
|
16
|
+
<p><%= @invoice.parties.seller_party.tax_identification.tax_identification_number %></p>
|
17
|
+
</div>
|
18
|
+
<div class="invoice-header-data">
|
19
|
+
<dl>
|
20
|
+
<dt>Factura num.</dt>
|
21
|
+
<dd><%= @invoice.invoices.first.invoice_header.invoice_number %></dd>
|
22
|
+
<dt>Fecha factura</dt>
|
23
|
+
<dd><%= @invoice.invoices.first.invoice_issue_data.issue_date %></dd>
|
24
|
+
</dl>
|
25
|
+
</div>
|
26
|
+
<div class="buyer-data">
|
27
|
+
<dl>
|
28
|
+
<dt>Facturar a</dt>
|
29
|
+
<dd>
|
30
|
+
<p class="name"><%= @invoice.parties.buyer_party.legal_entity.corporate_name %></p>
|
31
|
+
<p><%= @invoice.parties.buyer_party.legal_entity.address_in_spain.address %></p>
|
32
|
+
<p><%= @invoice.parties.buyer_party.legal_entity.address_in_spain.post_code %> <%= @invoice.parties.buyer_party.legal_entity.address_in_spain.town %></p>
|
33
|
+
<p><%= @invoice.parties.buyer_party.tax_identification.tax_identification_number %></p>
|
34
|
+
</dd>
|
35
|
+
</div>
|
36
|
+
<table class="invoice-details">
|
37
|
+
<colgroup>
|
38
|
+
<col class="col1"/>
|
39
|
+
<col class="col2"/>
|
40
|
+
</colgroup>
|
41
|
+
<thead>
|
42
|
+
<tr>
|
43
|
+
<th>Concepto</th>
|
44
|
+
<th>Importe</th>
|
45
|
+
</tr>
|
46
|
+
</thead>
|
47
|
+
<tbody class="invoice-items">
|
48
|
+
<% for item in @invoice.invoices.first.items %>
|
49
|
+
<tr>
|
50
|
+
<td class="description"><%= item.item_description %></td>
|
51
|
+
<td class="amount"><%= to_currency(item.total_cost) %></td>
|
52
|
+
</tr>
|
53
|
+
<% end %>
|
54
|
+
<% (8 - @invoice.invoices.first.items.size).times do %>
|
55
|
+
<tr><td class="description"></td><td class="amount"></td></tr>
|
56
|
+
<% end %>
|
57
|
+
</tbody>
|
58
|
+
<tbody class="invoice-subtotal">
|
59
|
+
<tr>
|
60
|
+
<td class="description">Base imponible</td>
|
61
|
+
<td class="amount"><%= to_currency(@invoice.invoices.first.invoice_totals.total_gross_amount_before_taxes) %></td>
|
62
|
+
</tr>
|
63
|
+
</tbody>
|
64
|
+
<tbody class="invoice-taxes">
|
65
|
+
<tr>
|
66
|
+
<td class="description">IRPF 15%</td>
|
67
|
+
<td class="amount">-97.50 €</td>
|
68
|
+
</tr>
|
69
|
+
</tbody>
|
70
|
+
<tbody class="invoice-total">
|
71
|
+
<tr>
|
72
|
+
<td class="description">TOTAL</td>
|
73
|
+
<td class="amount"><%= to_currency(@invoice.invoices.first.invoice_totals.invoice_total) %></td>
|
74
|
+
</tr>
|
75
|
+
</tbody>
|
76
|
+
</table>
|
77
|
+
<div class="footer">
|
78
|
+
<p>Pago: 30 días de factura</p>
|
79
|
+
<p>
|
80
|
+
Transferencia bancaria:<br/>
|
81
|
+
1234 5678 90 1234567890
|
82
|
+
</p>
|
83
|
+
</div>
|
84
|
+
</div>
|
85
|
+
</body>
|
86
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: facturae_print
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Alvaro Bautista
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-23 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: nokogiri
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 4
|
33
|
+
- 4
|
34
|
+
version: 1.4.4
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: erubis
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 27
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 6
|
49
|
+
- 6
|
50
|
+
version: 2.6.6
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: wkhtmltopdf-binary
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 17
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
- 9
|
65
|
+
- 5
|
66
|
+
- 1
|
67
|
+
version: 0.9.5.1
|
68
|
+
type: :runtime
|
69
|
+
version_requirements: *id003
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: pdfkit
|
72
|
+
prerelease: false
|
73
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
hash: 11
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
- 5
|
82
|
+
- 0
|
83
|
+
version: 0.5.0
|
84
|
+
type: :runtime
|
85
|
+
version_requirements: *id004
|
86
|
+
- !ruby/object:Gem::Dependency
|
87
|
+
name: thor
|
88
|
+
prerelease: false
|
89
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 43
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
- 14
|
98
|
+
- 6
|
99
|
+
version: 0.14.6
|
100
|
+
type: :runtime
|
101
|
+
version_requirements: *id005
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: rspec
|
104
|
+
prerelease: false
|
105
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 31
|
111
|
+
segments:
|
112
|
+
- 2
|
113
|
+
- 4
|
114
|
+
- 0
|
115
|
+
version: 2.4.0
|
116
|
+
type: :development
|
117
|
+
version_requirements: *id006
|
118
|
+
description: facturae_print translates a facturae xml file into an understandable HTML or PDF file
|
119
|
+
email:
|
120
|
+
- alvarobp@gmail.com
|
121
|
+
executables:
|
122
|
+
- facturae_print
|
123
|
+
extensions: []
|
124
|
+
|
125
|
+
extra_rdoc_files: []
|
126
|
+
|
127
|
+
files:
|
128
|
+
- .gitignore
|
129
|
+
- Gemfile
|
130
|
+
- LICENSE
|
131
|
+
- README.md
|
132
|
+
- Rakefile
|
133
|
+
- bin/facturae_print
|
134
|
+
- facturae_print.gemspec
|
135
|
+
- lib/facturae_print.rb
|
136
|
+
- lib/facturae_print/cli.rb
|
137
|
+
- lib/facturae_print/core_ext/string.rb
|
138
|
+
- lib/facturae_print/invoice.rb
|
139
|
+
- lib/facturae_print/renderers/html_renderer.rb
|
140
|
+
- lib/facturae_print/renderers/html_renderer_helpers.rb
|
141
|
+
- lib/facturae_print/renderers/pdf_renderer.rb
|
142
|
+
- lib/facturae_print/version.rb
|
143
|
+
- lib/facturae_print/xml_objectifier.rb
|
144
|
+
- spec/fixtures/facturae.xml
|
145
|
+
- spec/invoice_spec.rb
|
146
|
+
- spec/renderers/html_renderer_spec.rb
|
147
|
+
- spec/renderers/pdf_renderer_spec.rb
|
148
|
+
- spec/spec_helper.rb
|
149
|
+
- spec/xml_objectifier_spec.rb
|
150
|
+
- templates/default.css
|
151
|
+
- templates/default.eruby
|
152
|
+
has_rdoc: true
|
153
|
+
homepage: ""
|
154
|
+
licenses: []
|
155
|
+
|
156
|
+
post_install_message:
|
157
|
+
rdoc_options: []
|
158
|
+
|
159
|
+
require_paths:
|
160
|
+
- lib
|
161
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
162
|
+
none: false
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
hash: 3
|
167
|
+
segments:
|
168
|
+
- 0
|
169
|
+
version: "0"
|
170
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
|
+
none: false
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
hash: 3
|
176
|
+
segments:
|
177
|
+
- 0
|
178
|
+
version: "0"
|
179
|
+
requirements: []
|
180
|
+
|
181
|
+
rubyforge_project:
|
182
|
+
rubygems_version: 1.4.2
|
183
|
+
signing_key:
|
184
|
+
specification_version: 3
|
185
|
+
summary: facturae_print translates a facturae xml file into an understandable HTML or PDF file
|
186
|
+
test_files:
|
187
|
+
- spec/fixtures/facturae.xml
|
188
|
+
- spec/invoice_spec.rb
|
189
|
+
- spec/renderers/html_renderer_spec.rb
|
190
|
+
- spec/renderers/pdf_renderer_spec.rb
|
191
|
+
- spec/spec_helper.rb
|
192
|
+
- spec/xml_objectifier_spec.rb
|