facturae_print 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|