sunat_books 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e08f90e66a2cb035ea0747c2e90ab0717fe01fdd
4
+ data.tar.gz: 66e781fabac6fb3126919c07e661f17f4207b42b
5
+ SHA512:
6
+ metadata.gz: 51e5c9ae81c79fa4176aa6548f4dbbf11f4ee168e653685a79fb2d273436edf34fce09043265bdb2bb87f68bbb4083939777144f959a4b3b42c3e90356b2e544
7
+ data.tar.gz: a5bdeb8c98c009f53f7beff00ed0f7b0228087c9437c438f1aba94e2dedd477a3b7a0f97e94540ba99f5e2853e957a0973597b4b00ef03c544694715fadfde44
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.swp
2
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby '2.3.1'
4
+
5
+ gemspec
6
+
7
+ gem 'pry'
data/Gemfile.lock ADDED
@@ -0,0 +1,48 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sunat_books (0.0.1)
5
+ activesupport
6
+ i18n
7
+ prawn
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (5.0.0.1)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (~> 0.7)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ clap (1.0.0)
18
+ coderay (1.1.1)
19
+ concurrent-ruby (1.0.2)
20
+ cutest (1.2.3)
21
+ clap
22
+ i18n (0.7.0)
23
+ method_source (0.8.2)
24
+ minitest (5.9.0)
25
+ pdf-core (0.6.1)
26
+ prawn (2.1.0)
27
+ pdf-core (~> 0.6.1)
28
+ ttfunk (~> 1.4.0)
29
+ pry (0.10.4)
30
+ coderay (~> 1.1.0)
31
+ method_source (~> 0.8.1)
32
+ slop (~> 3.4)
33
+ slop (3.6.0)
34
+ thread_safe (0.3.5)
35
+ ttfunk (1.4.0)
36
+ tzinfo (1.2.2)
37
+ thread_safe (~> 0.1)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ cutest
44
+ pry
45
+ sunat_books!
46
+
47
+ BUNDLED WITH
48
+ 1.12.5
data/Makefile ADDED
@@ -0,0 +1,7 @@
1
+ .PHONY: test
2
+
3
+ console:
4
+ irb -Ilib -rsunat_books
5
+
6
+ test:
7
+ cutest test/*.rb
data/README.mkd ADDED
@@ -0,0 +1,37 @@
1
+ # Sunat Books
2
+ A ruby gem for get accounting books for [SUNAT](https://www.sunat.gob.pe)
3
+
4
+ ## Install
5
+ You can install via
6
+ ```
7
+ gem install sunat_books
8
+ ```
9
+ or by adding to your Gemfile
10
+ ```
11
+ gem 'sunat_books'
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```ruby
17
+ require 'sunat_books'
18
+ ```
19
+
20
+ to get a pdf format
21
+
22
+ ```ruby
23
+ pdf = Books::Buys.new(company, tickets, view_context, month, year)
24
+ pdf.render
25
+ ```
26
+
27
+ to get the txt file for electronic books
28
+
29
+ ```ruby
30
+ ple = PleBooks::Buys.new(ruc, tickets, month, year)
31
+ ```
32
+
33
+
34
+ https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/numeric/conversions.rb
35
+
36
+ get support for otf font in prawn
37
+ https://github.com/prawnpdf/prawn/issues/893
data/lib/books/base.rb ADDED
@@ -0,0 +1,212 @@
1
+ require 'prawn'
2
+ require 'yaml'
3
+ require 'active_support/all'
4
+
5
+ module Books
6
+ class Base < Prawn::Document
7
+ include ActiveSupport::NumberHelper
8
+
9
+ MONTHS = { 1 => "Enero", 2 => "Febrero", 3 => "marzo", 4 => "abril",
10
+ 5 => "mayo", 6 => "junio", 7 => "julio", 8 => "agosto",
11
+ 9 => "setiembre", 10 => "octubre", 11 => "noviembre",
12
+ 12 => "diciembre" }
13
+
14
+ def formated_number float
15
+ number_to_currency(float, unit: '')
16
+ end
17
+
18
+ def add_align aligns, options, key
19
+ aligns.each do |a|
20
+ if a[key] != nil
21
+ options[:cell_style] = options[:cell_style].merge({align: a[key][0].to_sym})
22
+ end
23
+ end
24
+ end
25
+
26
+ def txt txt
27
+ text txt, size: 8
28
+ end
29
+
30
+ def sub_head hash, book_name, blayout
31
+ arr = nil
32
+ current_key = nil
33
+ column_widths = {}
34
+ hash.each do |key, value|
35
+ k = I18n.t("books.#{book_name}.#{key}").mb_chars.upcase.to_s
36
+ v = value.collect { |s| I18n.t("books.#{book_name}.#{s}").mb_chars.upcase.to_s}
37
+ arr = [[{content: k, colspan: value.length}], v]
38
+ current_key = key
39
+ end
40
+
41
+ widths = blayout["widths"]
42
+ if !widths.nil?
43
+ widths.each do |w|
44
+ if w[current_key] != nil
45
+ column_widths = w[current_key].flatten
46
+ end
47
+ end
48
+ end
49
+ if column_widths.size != 0
50
+ multihead = make_table( arr, cell_style: {borders: [], size: 5, align: :center},
51
+ column_widths: column_widths) do
52
+ cells.padding = 1
53
+ end
54
+ else
55
+ multihead = make_table( arr,
56
+ cell_style: {borders: [], size: 5, width: 22, padding: 1, align: :center})
57
+ end
58
+ end
59
+
60
+ def get_period month, year
61
+ "#{MONTHS[month.to_i].upcase} #{year}"
62
+ end
63
+
64
+ def book_title title
65
+ text title, align: :center, size: 8
66
+ end
67
+
68
+ def book_header period, ruc, name, title=nil
69
+ move_down 5
70
+ #txt "PERIODO: #{period}"
71
+ #txt "RUC: #{ruc}"
72
+ #txt "APELLIDOS Y NOMBRES, DENOMINACIÓN O RAZÓN SOCIAL: #{name.upcase}"
73
+ txt "#{name.upcase}"
74
+ txt "RUC: #{ruc}"
75
+ book_title("#{title} - #{period}")
76
+ move_down 5
77
+ end
78
+
79
+ def zero
80
+ formated_number(0)
81
+ end
82
+
83
+ def table_head fields, book_name, layout
84
+ thead = []
85
+ fields.each do |h|
86
+ if h.class == Hash
87
+ r = sub_head(h, book_name, layout)
88
+ thead << r
89
+ else
90
+ thead << I18n.t("books.#{book_name}.#{h}").mb_chars.upcase.to_s
91
+ end
92
+ end
93
+ thead
94
+ end
95
+
96
+ def table_body fields, ticket, widths, aligns
97
+ tbody = []
98
+ fields.each do |f|
99
+ if f.class == Hash
100
+ f.each do |key, value|
101
+ v = value.collect do |s|
102
+ begin
103
+ value = ticket.send(s)
104
+ value = formated_number(value) if value.class == BigDecimal
105
+ rescue
106
+ value = ""
107
+ end
108
+ value
109
+ end
110
+ options = {cell_style: {borders: [], size: 5}}
111
+ column_widths = nil
112
+ if !widths.nil?
113
+ widths.each do |w|
114
+ if w[key] != nil
115
+ column_widths = w[key].flatten
116
+ end
117
+ end
118
+ end
119
+ if column_widths != nil
120
+ options = options.merge({column_widths: column_widths})
121
+ else
122
+ options[:cell_style] = options[:cell_style].merge({width: 28})
123
+ end
124
+ if !aligns.nil?
125
+ add_align(aligns, options, key)
126
+ end
127
+ arr = make_table( [v], options)
128
+ tbody << arr
129
+ end
130
+ else
131
+ begin
132
+ value = ticket.send(f)
133
+ rescue
134
+ value = ""
135
+ end
136
+ value = formated_number(value) if value.class == BigDecimal
137
+ tbody << value
138
+ end
139
+ end
140
+ tbody
141
+ end
142
+
143
+ # diary
144
+ def get_counts tickets
145
+ arr = tickets.map { |t| t.uniq_counts }
146
+ arr = arr.flatten.uniq.sort
147
+ end
148
+
149
+ def get_mother_counts tickets
150
+ arr = tickets.map { |t| t.uniq_mother_counts }
151
+ arr = arr.flatten.uniq.sort
152
+ end
153
+
154
+ def get_value ticket, count
155
+ # active_amount = ticket.get_amount_by_position(count)
156
+ # pasive_amount = ticket.get_amount_by_position(count, false)
157
+ active_amount = ticket.get_amount_by_mother_count(count)
158
+ pasive_amount = ticket.get_amount_by_mother_count(count, false)
159
+ # if count === '401' && ticket.operation_type == 'compras'
160
+ # amount = amount * (-1)
161
+ # end
162
+ amount = active_amount - pasive_amount
163
+ end
164
+
165
+ def get_row_sums tickets, counts, total_sums
166
+ # given an array of counts and tickets get sums by each count
167
+ row_counts = get_mother_counts tickets
168
+ count_sums = row_counts.map { |count| CountSum.new(count) }
169
+
170
+ # get totals
171
+ tickets.each do |ticket|
172
+ count_sums.each do |count_sum|
173
+ count_sum.add get_value(ticket, count_sum.count)
174
+ end
175
+ end
176
+
177
+ # get ordered row
178
+ row_data = []
179
+ counts.each_with_index do |count, i|
180
+ sum_count = nil
181
+ count_sums.each do |count_sum|
182
+ sum_count = count_sum if count_sum.count == count
183
+ end
184
+
185
+ if sum_count
186
+ value = sum_count.total
187
+ else
188
+ value = 0
189
+ end
190
+ total_sums[i].add value
191
+ row_data << { content: formated_number(value), align: :right }
192
+ end
193
+ row_data
194
+ end
195
+
196
+ def make_sub_table content, width=nil
197
+ options = {cell_style: {width: width, size: 5, borders: [], align: :right}}
198
+ content_row = []
199
+ content.each {|c| content_row << formated_number(c) }
200
+ make_table([content_row],options)
201
+ end
202
+
203
+ # Utils
204
+ def get_date year, month, day
205
+ parse_day(Date.new(year.to_i, month.to_i, day))
206
+ end
207
+
208
+ def parse_day day
209
+ day.strftime("%d-%m").to_s
210
+ end
211
+ end
212
+ end
data/lib/books/buys.rb ADDED
@@ -0,0 +1,120 @@
1
+ require 'books/base'
2
+
3
+ module Books
4
+ class Buys < Base
5
+ attr_accessor :pages
6
+
7
+ def initialize(company, tickets, view, month, year)
8
+ # company => an object that respond to ruc and name methods
9
+ # tickets => an array of objects that respond to a layout's methods
10
+ # view => a view context
11
+ # month => a number that represent a month
12
+ # year => a number that represent a year
13
+ super(page_layout: :landscape, margin: [5], page_size: "A4")
14
+ @view = view
15
+ @company = company
16
+ @period = get_period(month, year)
17
+ @tickets = tickets
18
+ @pages = {}
19
+ @book_name = self.class.name.downcase.sub("books::", "")
20
+ dir = File.dirname(__FILE__)
21
+ @blayout = YAML.load_file("#{dir}/layouts/#{@book_name}.yml")
22
+ @page_max = 27
23
+
24
+ repeat(:all) do
25
+ canvas do
26
+ bounding_box([bounds.left + 10, bounds.top - 10], width: 800) do
27
+ book_header @period, @company.ruc, @company.name, "REGISTRO DE COMPRAS"
28
+ end
29
+ end
30
+ end
31
+
32
+ bounding_box([bounds.left + 3, bounds.top - 45], width: 800, height: 530) do
33
+ book_body
34
+ end
35
+ end
36
+
37
+ def final_row foot_line_text, page
38
+ [ {content: foot_line_text, colspan: 5 },
39
+ make_sub_table([page[:bi_sum], page[:igv_sum]], 32),
40
+ make_sub_table([zero, zero], 25),
41
+ make_sub_table([zero, zero], 25),
42
+ formated_number(page[:non_taxable]),
43
+ zero, zero,
44
+ formated_number(page[:total_sum]) ]
45
+ end
46
+
47
+ def book_body
48
+ # get total number of tickets
49
+ length = @tickets.length
50
+ page_num = (length / 27.0).ceil
51
+ page_num.times do |i|
52
+ pages[i + 1] = {
53
+ page_number: i + 1,
54
+ length: 0,
55
+ bi_sum: BigDecimal(0)
56
+ }
57
+ end
58
+
59
+ move_down 5
60
+ fields = @blayout["headers"]
61
+ widths = @blayout["widths"]
62
+ aligns = @blayout["align"]
63
+ data = []
64
+ data << table_head(fields, @book_name, @blayout)
65
+
66
+ n = 1
67
+ bi_sum = BigDecimal(0)
68
+ igv_sum = BigDecimal(0)
69
+ total_sum = BigDecimal(0)
70
+ non_taxable = BigDecimal(0)
71
+
72
+
73
+ if length > 0
74
+ @tickets.each do |ticket|
75
+
76
+ if @pages[n][:length] < @page_max
77
+ page = @pages[n]
78
+ page[:length] += 1
79
+ else
80
+ data << final_row('VIENEN', @pages[n])
81
+
82
+ n += 1
83
+ page = @pages[n]
84
+ page[:length] += 2
85
+ end
86
+
87
+ data << table_body(fields, ticket, widths, aligns)
88
+
89
+ bi_sum += ticket.taxable_to_taxable_export_bi
90
+ igv_sum += ticket.taxable_to_taxable_export_igv
91
+ total_sum += ticket.total_operation_buys
92
+ non_taxable += ticket.non_taxable unless ticket.non_taxable.nil?
93
+ page[:bi_sum] = bi_sum.round(2)
94
+ page[:igv_sum] = igv_sum.round(2)
95
+ page[:total_sum] = total_sum.round(2)
96
+ page[:non_taxable] = non_taxable.round(2)
97
+ if page[:length] == @page_max && @tickets.last != ticket
98
+ data << final_row('VAN', page)
99
+ elsif @tickets.last == ticket
100
+ data << final_row('TOTAL', page)
101
+ end
102
+ end
103
+ else
104
+ data << [content: 'SIN MOVIMIENTO EN EL PERIODO', colspan: 5]
105
+ @pages[n] = {}
106
+ page = @pages[n]
107
+ page[:bi_sum] = zero
108
+ page[:igv_sum] = zero
109
+ page[:total_sum] = zero
110
+ page[:non_taxable] = zero
111
+ end
112
+
113
+ table(data, header: true, cell_style: {borders: [], size: 5, align: :right},
114
+ column_widths: {0 => 22, 1 => 35, 2 => 30, 8 => 30, 10 => 30,
115
+ 9 => 22, 11 => 33, 12 => 33}) do
116
+ row(0).borders = [:bottom, :top]
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,20 @@
1
+ module Books
2
+ class CountSum
3
+ def initialize count_number, initial_value=BigDecimal(0)
4
+ @sum = initial_value
5
+ @count_number = count_number
6
+ end
7
+
8
+ def add value
9
+ @sum += value
10
+ end
11
+
12
+ def count
13
+ @count_number
14
+ end
15
+
16
+ def total
17
+ @sum
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ headers:
2
+ - correlative
3
+ - operation_date
4
+ - pay_date
5
+ - document:
6
+ - doc_type
7
+ - document_serial
8
+ - year_emition
9
+ - document_number
10
+ - supplier:
11
+ - supplier_document_type
12
+ - supplier_document_number
13
+ - supplier_name
14
+ - taxable_to_taxable_export:
15
+ - taxable_to_taxable_export_bi
16
+ - taxable_to_taxable_export_igv
17
+ - taxable_to_taxable_export_non_taxable:
18
+ - taxable_to_taxable_export_non_taxable_bi
19
+ - taxable_to_taxable_export_non_taxable_igv
20
+ - taxable_to_non_taxable:
21
+ - taxable_to_non_taxable_bi
22
+ - taxable_to_non_taxable_igv
23
+ - non_taxable
24
+ - isc
25
+ - other_taxs
26
+ - total_operation_buys
27
+ - foreign_pay_document_number
28
+ - detraction:
29
+ - detraction_number
30
+ - detraction_date
31
+ - exchange_rate
32
+ - debit_original_document:
33
+ - debit_original_document_date
34
+ - debit_original_document_type
35
+ - debit_original_document_serial
36
+ - debit_original_document_number
37
+ widths:
38
+ - document:
39
+ - [20, 23, 23 ,41]
40
+ - supplier:
41
+ - [15, 40, 57]
42
+ - taxable_to_taxable_export:
43
+ - [32, 32]
44
+ - taxable_to_taxable_export_non_taxable:
45
+ - [25, 25]
46
+ - taxable_to_non_taxable:
47
+ - [25, 25]
48
+ - detraction:
49
+ - [20, 25]
50
+ align:
51
+ - taxable_to_taxable_export:
52
+ - right
@@ -0,0 +1,36 @@
1
+ headers:
2
+ - correlative
3
+ - operation_date
4
+ - pay_date
5
+ - document:
6
+ - doc_type
7
+ - document_serial
8
+ - document_number
9
+ - client:
10
+ - client_document_type
11
+ - client_document_number
12
+ - client_name
13
+ - export_value
14
+ - taxable_bi #- bi_taxable_operation
15
+ - sale_non_taxable:
16
+ - exo
17
+ - inaf
18
+ - isc
19
+ - igv
20
+ - other_taxs
21
+ - total_operation_sales
22
+ - exchange_rate
23
+ - credit_origina_document:
24
+ - credit_original_document_date #
25
+ - credit_original_document_type
26
+ - credit_original_document_serial
27
+ - credit_original_document_number
28
+ widths:
29
+ - document:
30
+ - [20, 20, 40]
31
+ - client:
32
+ - [15, 40, 58]
33
+ - sale_non_taxable:
34
+ - [22, 22]
35
+ - credit_origina_document:
36
+ - [22, 22, 22, 22]
@@ -0,0 +1,114 @@
1
+ require 'books/base'
2
+
3
+ module Books
4
+ class Sales < Base
5
+ def initialize(company, tickets, view, month, year)
6
+ super(page_layout: :landscape, margin: [5], page_size: "A4")
7
+ @view = view
8
+ @company = company
9
+ @period = get_period(month, year)
10
+ @pages = {}
11
+ @tickets = tickets
12
+ @book_name = self.class.name.downcase.sub("books::", "")
13
+ dir = File.dirname(__FILE__)
14
+ @blayout = YAML.load_file("#{dir}/layouts/#{@book_name}.yml")
15
+ @page_max = 29
16
+
17
+ repeat(:all) do
18
+ canvas do
19
+ bounding_box([bounds.left + 10, bounds.top - 10], width: 800) do
20
+ # book_title "REGISTRO DE VENTAS"
21
+ book_header @period, @company.ruc, @company.name, "REGISTRO DE VENTAS"
22
+ end
23
+ end
24
+ end
25
+
26
+ bounding_box([bounds.left + 3, bounds.top - 45], width: 800, height: 530) do
27
+ book_body
28
+ end
29
+
30
+ repeat(:all, dynamic: true) do
31
+ canvas do
32
+ bounding_box([235, 50], width: 700) do
33
+ # book_footer
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ def book_body
40
+ length = @tickets.length
41
+ page_num = (length / 29.0).ceil
42
+ page_num.times do |i|
43
+ @pages[i + 1] = {
44
+ page_number: i + 1,
45
+ length: 0,
46
+ bi_sum: BigDecimal(0)
47
+ }
48
+ end
49
+
50
+ move_down 5
51
+ fields = @blayout["headers"]
52
+ widths = @blayout["widths"]
53
+ aligns = @blayout["align"]
54
+ data = []
55
+ data << table_head(fields, @book_name, @blayout)
56
+
57
+ n = 1
58
+ bi_sum = BigDecimal(0)
59
+ igv_sum = BigDecimal(0)
60
+ total_sum = BigDecimal(0)
61
+ non_taxable = BigDecimal(0)
62
+
63
+ if length > 0
64
+ @tickets.each do |ticket|
65
+
66
+ if @pages[n][:length] < @page_max
67
+ page = @pages[n]
68
+ page[:length] += 1
69
+ else
70
+ data << final_row('VIENEN', @pages[n])
71
+ page = @pages[n + 1]
72
+ n += 1
73
+ page[:length] += 2
74
+ end
75
+
76
+ data << table_body(fields, ticket, widths, aligns)
77
+
78
+ bi_sum += ticket.taxable_bi
79
+ igv_sum += ticket.igv
80
+ total_sum += ticket.total_operation_sales
81
+ page[:bi_sum] = bi_sum.round(2)
82
+ page[:igv_sum] = igv_sum.round(2)
83
+ page[:total_sum] = total_sum.round(2)
84
+ if page[:length] == @page_max && @tickets.last != ticket
85
+ data << final_row('VAN', page)
86
+ elsif @tickets.last == ticket
87
+ data << final_row('TOTAL', page)
88
+ end
89
+ end
90
+ else
91
+ data << [content: 'SIN MOVIMIENTO EN EL PERIODO', colspan: 5]
92
+ @pages[n] = {}
93
+ page = @pages[n]
94
+ page[:bi_sum] = zero
95
+ page[:igv_sum] = zero
96
+ page[:total_sum] = zero
97
+ end
98
+
99
+ table(data, header: true, cell_style: { borders: [], size: 5,
100
+ align: :right },
101
+ column_widths: {0 => 22, 1 => 35, 2 => 30, 5 => 27, 6 => 37,
102
+ 8 => 20, 9 => 33, 10 => 27, 11 => 35, 12 => 29}) do
103
+ row(0).borders = [:bottom, :top]
104
+ end
105
+ end
106
+
107
+ def final_row foot_line_text, page
108
+ [ {content: foot_line_text, colspan: 5}, zero,
109
+ formated_number(page[:bi_sum]), make_sub_table([zero, zero], 22), zero,
110
+ formated_number(page[:igv_sum]), zero,
111
+ formated_number(page[:total_sum])]
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,149 @@
1
+ require 'books/base'
2
+ require 'books/count_sum'
3
+
4
+ module Books
5
+ class SimplifiedDiary < Base
6
+ def initialize company, tickets, view, month, year
7
+ super(page_layout: :landscape, margin: [5], page_size: "A4")
8
+ @view = view
9
+ @company = company
10
+ @tickets = tickets
11
+ #@book_name = self.class.name.downcase.sub("books::", "")
12
+ #dir = File.dirname(__FILE__)
13
+ #@blayout = YAML.load_file("#{dir}/layouts/#{@book_name}.yml")
14
+ counts = get_mother_counts @tickets
15
+ total_sums = counts.map { |count| CountSum.new(count) }
16
+
17
+ (month.to_i..12).each do |m|
18
+ start_new_page unless m == month.to_i
19
+ period = get_period(m, year)
20
+
21
+ bounding_box([bounds.left + 3, bounds.top - 10], width: 815, height: 510) do
22
+ book_body m, year, total_sums, 20, period
23
+ end
24
+ end
25
+ end
26
+
27
+ def book_body month, year, total_sums, max_column=nil, period=nil
28
+ data = []
29
+ tickets = @tickets.where(period_month: month, period_year: year)
30
+
31
+ # header
32
+ # counts = get_counts @tickets
33
+ counts = get_mother_counts @tickets
34
+ data << ['FECHA', 'OPERACIÓN', counts].flatten
35
+
36
+ # body
37
+
38
+ # initial entry
39
+ initial = tickets.where(operation_type: 'inicial')
40
+ if initial.length > 0
41
+ initial_data = get_row_sums(initial, counts, total_sums)
42
+ else
43
+ initial_data = []
44
+ total_sums.map do |sum|
45
+ initial_data << { content: formated_number(sum.total), align: :right }
46
+ end
47
+ end
48
+ date = get_date(year.to_i, month.to_i, 1)
49
+ data << [date, 'ASIENTO INICIAL DEL PERIODO', initial_data].flatten
50
+
51
+ if tickets.length > 0
52
+ sales = tickets.where(operation_type: 'ventas')
53
+ if sales.count > 0
54
+ # sales entry
55
+ sales_row = get_row_sums(sales, counts, total_sums)
56
+ data << [get_date(year.to_i, month.to_i, -1), 'VENTAS DEL PERIODO', sales_row].flatten
57
+ end
58
+
59
+ buys = tickets.where(operation_type: 'compras')
60
+ if buys.count > 0
61
+ # buys entry
62
+ buys_row = get_row_sums(buys, counts, total_sums)
63
+ data << [get_date(year.to_i, month.to_i, -1), 'COMPRAS DEL PERIODO', buys_row].flatten
64
+ end
65
+
66
+ # other entries
67
+ others = tickets.where(operation_type: 'otros')
68
+ # others_row = get_row_sums(others, counts, total_sums)
69
+ others.each do |ticket|
70
+ ticket_data = []
71
+ counts.each_with_index do |count, i|
72
+ if ticket.uniq_mother_counts.include? count
73
+ value = get_value(ticket, count)
74
+ else
75
+ value = 0
76
+ end
77
+ total_sums[i].add value
78
+ ticket_data << { content: formated_number(value), align: :right }
79
+ end
80
+ data << [parse_day(ticket.operation_date), ticket.reference, ticket_data].flatten
81
+ end
82
+
83
+ # cierre entry
84
+ close = tickets.where(operation_type: 'cierre')
85
+ close.each do |ticket|
86
+ ticket_data = []
87
+ counts.each_with_index do |count, i|
88
+ if ticket.uniq_mother_counts.include? count
89
+ value = get_value(ticket, count)
90
+ else
91
+ value = 0
92
+ end
93
+ total_sums[i].add value
94
+ ticket_data << { content: formated_number(value), align: :right }
95
+ end
96
+ data << [parse_day(ticket.operation_date), ticket.reference, ticket_data].flatten
97
+ end
98
+ else
99
+ data << [{content: 'SIN MOVIMIENTO EN EL PERIODO', colspan: 5}]
100
+ end
101
+
102
+ # totals
103
+ total_data = []
104
+ total_sums.map do |sum|
105
+ total_data << { content: formated_number(sum.total), align: :right }
106
+ end
107
+ data << [{content: 'TOTALES', colspan: 2}, total_data].flatten
108
+
109
+ book_header period, @company.ruc, @company.name, "LIBRO DIARIO - FORMATO SIMPLIFICADO"
110
+
111
+ if data.first.count > max_column
112
+ tmp0 = []
113
+ tmp1 = []
114
+
115
+ data.each do |column|
116
+ if column == data.last
117
+ first_page = column.first(max_column - 1)
118
+ tmp0 << first_page
119
+ next_page = [ column.first ] + (column[(max_column -1)..column.length])
120
+ tmp1 << next_page
121
+ else
122
+ if column.length < max_column
123
+ tmp0 << column
124
+ else
125
+ first_page = column.first(max_column)
126
+ tmp0 << first_page
127
+
128
+ # TODO: make the same for more than 2 pages
129
+ next_page = column.first(2) + (column[max_column..column.length])
130
+ tmp1 << next_page
131
+ end
132
+ end
133
+ end
134
+
135
+ table(tmp0, header: true, cell_style: {borders: [], size: 6},
136
+ column_widths: { 1 => 73 })
137
+ start_new_page
138
+ book_header period, @company.ruc, @company.name, "LIBRO DIARIO - FORMATO SIMPLIFICADO"
139
+ table(tmp1, header: true, cell_style: {borders: [], size: 6},
140
+ column_widths: { 1 => 73 })
141
+
142
+ else
143
+
144
+ table(data, header: true, cell_style: {borders: [], size: 6},
145
+ column_widths: { 1 => 73 })
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,60 @@
1
+ require 'csv'
2
+
3
+ module PleBooks
4
+ class Base
5
+ attr_accessor :file
6
+
7
+ def ple_book_name uid, ruc, month, year, operations_state=nil, content=nil, currency=nil
8
+ code = book_code(uid)
9
+ code_oportunity = '00' # TODO: case for 'inventarios y balances'
10
+ operations_state ||= 1 # 0, 1, 2
11
+ content ||= 1 # 1 ,0
12
+ currency ||= 1 # 1, 2
13
+ "LE#{ruc}#{year}#{month}00#{code}#{code_oportunity}#{operations_state}#{content}#{currency}1"
14
+ end
15
+
16
+ def book_code uid
17
+ dir = File.dirname(__FILE__)
18
+ path = "#{dir}/book_codes.csv"
19
+ code = ""
20
+ CSV.foreach(path) do |row|
21
+ if row[0] == uid
22
+ code = row[2]
23
+ break
24
+ end
25
+ end
26
+ code
27
+ end
28
+
29
+ def path
30
+ dir = File.dirname(__FILE__)
31
+ tmp_path = "#{dir}/tmp/"
32
+ Dir.mkdir(tmp_path) unless Dir.exists?(tmp_path)
33
+ tmp_path
34
+ end
35
+
36
+ def get_file(tickets, fields, filename)
37
+ FileUtils.touch("#{filename}")
38
+
39
+ send("file=", filename)
40
+
41
+ tickets.each_with_index do |ticket, i|
42
+ ticket_data = ""
43
+
44
+ fields.each do |field|
45
+ begin
46
+ value = ticket.send(field)
47
+ rescue
48
+ value = ""
49
+ end
50
+ ticket_data << "#{value}|"
51
+ end
52
+
53
+ mode = (i == 0 ? "w+" : "a+")
54
+ File.open("#{filename}", mode) do |txt|
55
+ txt.puts(ticket_data)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,48 @@
1
+ 1.1,LIBRO CAJA Y BANCOS - DETALLE DE LOS MOVIMIENTOS DEL EFECTIVO,010100
2
+ 1.2,LIBRO CAJA Y BANCOS - DETALLE DE LOS MOVIMIENTOS DE LA CUENTA CORRIENTE,010200
3
+ 3.1,LIBRO DE INVENTARIOS Y BALANCES - ESTADO DE SITUACIÓN FINANCIERA,030100
4
+ 3.2,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 10 EFECTIVO Y EQUIVALENTES DE EFECTIVO (2),030200
5
+ 3.3,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 12 CUENTAS POR COBRAR COMERCIALES – TERCEROS Y 13 CUENTAS POR COBRAR COMERCIALES – RELACIONADAS,030300
6
+ 3.4,"LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 14 CUENTAS POR COBRAR AL PERSONAL, A LOS ACCIONISTAS (SOCIOS), DIRECTORES Y GERENTES (2)",030400
7
+ 3.5,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 16 CUENTAS POR COBRAR DIVERSAS - TERCEROS O CUENTA 17 - CUENTAS POR COBRAR DIVERSAS - RELACIONADAS,030500
8
+ 3.6,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 19 ESTIMACIÓN DE CUENTAS DE COBRANZA DUDOSA,030600
9
+ 3.7,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 20 - MERCADERIAS Y LA CUENTA 21 - PRODUCTOS TERMINADOS (2),030700
10
+ 3.8,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 30 INVERSIONES MOBILIARIAS (2),030800
11
+ 3.9,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 34 - INTANGIBLES,030900
12
+ 3.11,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 41 REMUNERACIONES Y PARTICIPACIONES POR PAGAR (2),031100
13
+ 3.12,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 42 CUENTAS POR PAGAR COMERCIALES – TERCEROS Y LA CUENTA 43 CUENTAS POR PAGAR COMERCIALES – RELACIONADAS ,031200
14
+ 3.13,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 46 CUENTAS POR PAGAR DIVERSAS – TERCEROS Y DE LA CUENTA 47 CUENTAS POR PAGAR DIVERSAS – RELACIONADAS,031300
15
+ 3.14,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 47 - BENEFICIOS SOCIALES DE LOS TRABAJADORES (PCGR) - NO APLICABLE PARA EL PCGE (2),031400
16
+ 3.15,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 37 ACTIVO DIFERIDO Y DE LA CUENTA 49 PASIVO DIFERIDO,031500
17
+ 3.16,LIBRO DE INVENTARIOS Y BALANCES - DETALLE DEL SALDO DE LA CUENTA 50 CAPITAL,031600
18
+ 3.16.1,DETALLE DEL SALDO DE LA CUENTA 50 - CAPITAL ,031600
19
+ 3.16.2,ESTRUCTURA DE LA PARTICIPACIÓN ACCIONARIA O DE PARTICIPACIONES SOCIALES,031600
20
+ 3.17,LIBRO DE INVENTARIOS Y BALANCES - BALANCE DE COMPROBACIÓN,031700
21
+ 3.18,LIBRO DE INVENTARIOS Y BALANCES - ESTADO DE FLUJOS DE EFECTIVO - MÉTODO DIRECTO,031800
22
+ 3.19,LIBRO DE INVENTARIOS Y BALANCES - ESTADO DE CAMBIOS EN EL PATRIMONIO NETO,031900
23
+ 3.20,LIBRO DE INVENTARIOS Y BALANCES - ESTADO DE RESULTADOS,032000
24
+ 3.23,LIBRO DE INVENTARIOS Y BALANCES - NOTAS A LOS ESTADOS FINANCIEROS (3),032300
25
+ 3.24,LIBRO DE INVENTARIOS Y BALANCES - ESTADO DE RESULTADOS INTEGRALES,032400
26
+ 3.25,LIBRO DE INVENTARIOS Y BALANCES - ESTADO DE FLUJOS DE EFECTIVO - MÉTODO INDIRECTO,32500
27
+ 4.1,LIBRO DE RETENCIONES INCISO E) Y F) DEL ART. 34° DE LA LEY DEL IMPUESTO A LA RENTA,040100
28
+ 5.1,LIBRO DIARIO,050100
29
+ 5.3,LIBRO DIARIO - DETALLE DEL PLAN CONTABLE UTILIZADO,050300
30
+ 5.2,LIBRO DIARIO DE FORMATO SIMPLIFICADO,050200
31
+ 5.4,LIBRO DIARIO DE FORMATO SIMPLIFICADO - DETALLE DEL PLAN CONTABLE UTILIZADO,050400
32
+ 6.1,LIBRO MAYOR,060100
33
+ 7.1,REGISTRO DE ACTIVOS FIJOS - DETALLE DE LOS ACTIVOS FIJOS REVALUADOS Y NO REVALUADOS,070100
34
+ 7.3,REGISTRO DE ACTIVOS FIJOS - DETALLE DE LA DIFERENCIA DE CAMBIO,070300
35
+ 7.4,REGISTRO DE ACTIVOS FIJOS - DETALLE DE LOS ACTIVOS FIJOS BAJO LA MODALIDAD DE ARRENDAMIENTO FINANCIERO AL 31.12,070400
36
+ 8.1,REGISTRO DE COMPRAS,080100
37
+ 8.2,REGISTRO DE COMPRAS - INFORMACIÓN DE OPERACIONES CON SUJETOS NO DOMICILIADOS,080200
38
+ 8.3,REGISTRO DE COMPRAS SIMPLIFICADO,080300
39
+ 9.1,REGISTRO DE CONSIGNACIONES - PARA EL CONSIGNADOR - CONTROL DE BIENES ENTREGADOS EN CONSIGNACIÓN,090100
40
+ 9.2,REGISTRO DE CONSIGNACIONES - PARA EL CONSIGNATARIO - CONTROL DE BIENES RECIBIDOS EN CONSIGNACIÓN,090200
41
+ 10.1,REGISTRO DE COSTOS - ESTADO DE COSTO DE VENTAS ANUAL,100100
42
+ 10.2,REGISTRO DE COSTOS - ELEMENTOS DEL COSTO MENSUAL,100200
43
+ 10.3,REGISTRO DE COSTOS - ESTADO DE COSTO DE PRODUCCION VALORIZADO ANUAL,100300
44
+ 10.4,REGISTRO DE COSTOS - CENTRO DE COSTOS,100400
45
+ 12.1,REGISTRO DEL INVENTARIO PERMANENTE EN UNIDADES FÍSICAS - DETALLE DEL INVENTARIO PERMANENTE EN UNIDADES FÍSICAS,120100
46
+ 13.1,REGISTRO DEL INVENTARIO PERMANENTE VALORIZADO - DETALLE DEL INVENTARIO VALORIZADO,130100
47
+ 14.1,REGISTRO DE VENTAS E INGRESOS,140100
48
+ 14.2,REGISTRO DE VENTAS E INGRESOS SIMPLIFICADO,140200
@@ -0,0 +1,33 @@
1
+ require 'ple_books/base'
2
+
3
+ module PleBooks
4
+ class Buys < Base
5
+ def initialize(ruc, tickets, month, year, options={})
6
+ # ruc => company's ruc in string format
7
+ # tickets => an array of objects that respond to a layout's methods
8
+ # month => a number that represent a month
9
+ # year => a number that represent a year
10
+ # options =>
11
+ # :yml => to define a custom layout file
12
+ # :layout => to define a custom name for a specific layout method
13
+
14
+ book_name = self.class.name.downcase.sub("plebooks::", "")
15
+ dir = File.dirname(__FILE__)
16
+ yml_path = options[:yml] || "#{dir}/layouts/#{book_name}.yml"
17
+ fields = YAML.load_file(yml_path)
18
+
19
+ if options[:layout]
20
+ options[:layout].each do |key, value|
21
+ i = fields.index(key.to_s)
22
+ fields.delete(key.to_s)
23
+ fields.insert(i, value)
24
+ end
25
+ end
26
+
27
+ content = tickets.length > 0 ? 1 : 0
28
+
29
+ filename = "#{path}#{ple_book_name('8.1', ruc, month, year, nil, content)}.txt"
30
+ get_file(tickets, fields, filename)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ - period # YYYYMM00
2
+ - cuo # Código Unico de Operación, software (max 40)
3
+ - correlative # 2 ..10
4
+ - operation_date # day # 'dd/mm/yyyy'
5
+ - pay_date # day # 'dd/mm/yyyy'
6
+ - document_type # 2
7
+ - document_serial # max 20
8
+ - dua_year_emition
9
+ - document_number # max 20
10
+ - total_diary_operation_non_credit # max 20
11
+ - provider_document_type
12
+ - provider_document_number # max 15
13
+ - provider_name # max 100
14
+ - document_bi_export_only
15
+ - document_igv_export_only
16
+ - document_bi_export_n_no_tax
17
+ - document_igv_export_n_no_tax
18
+ - document_bi_export_non_tax
19
+ - document_igv_export_non_tax
20
+ - document_non_tax
21
+ - documentn_isc
22
+ - document_other_tax
23
+ - document_total
24
+ - document_exchange_rate # 1 entero, 3 decimales
25
+ - modified_document_date
26
+ - modified_document_type # 2
27
+ - modified_document_serial
28
+ - modified_document_aduanas_dependency
29
+ - modified_document_number
30
+ - foreign_document_number
31
+ - detraction_date
32
+ - detraction_number
33
+ - marca_document_retention # retention ? '1' : '0'
34
+ - operation_status # current -> '0' '1', -<>?
@@ -0,0 +1,25 @@
1
+ - period
2
+ - cuo
3
+ - correlative
4
+ - operation_date
5
+ - pay_date
6
+ - document_type
7
+ - document_serial
8
+ - initial_document_number
9
+ - final_document_number
10
+ - client_document_type
11
+ - client_document_number
12
+ - client_name
13
+ - bi_taxable_operation
14
+ - igv_tax
15
+ - non_taxable
16
+ - total_operation
17
+ - currency_code
18
+ - exchange_rate
19
+ - original_document_date
20
+ - original_document_type
21
+ - original_document_serial
22
+ - original_document_number
23
+ - exchange_rate_error
24
+ - payment_way
25
+ - anotation_state
@@ -0,0 +1,14 @@
1
+ require 'ple_books/base'
2
+
3
+ module PleBooks
4
+ class Sales < Base
5
+ def initialize(ruc, tickets, month, year)
6
+ book_name = self.class.name.downcase.sub("plebooks::", "")
7
+ dir = File.dirname(__FILE__)
8
+ fields = YAML.load_file("#{dir}/layouts/#{book_name}.yml")
9
+
10
+ @filename = "#{path}#{ple_book_name('14.2', ruc, month, year)}.txt"
11
+ get_file(tickets, fields, @filename)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ require 'books/buys'
2
+ require 'books/sales'
3
+ require 'books/simplified_diary'
4
+ require 'ple_books/buys'
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "sunat_books"
3
+ s.version = "0.0.1"
4
+ s.summary = "SUNAT books"
5
+ s.description = s.summary
6
+ s.authors = ["César Carruitero"]
7
+ s.email = ["cesar@mozilla.pe"]
8
+ s.homepage = "https://github.com/ccarruitero/books"
9
+ s.license = "MPL"
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+
13
+ s.add_runtime_dependency "prawn"
14
+ s.add_runtime_dependency "i18n"
15
+ s.add_runtime_dependency "activesupport"
16
+
17
+ s.add_development_dependency "cutest"
18
+ end
@@ -0,0 +1,2 @@
1
+ - custom_field
2
+ - other_field
@@ -0,0 +1,11 @@
1
+ require 'pry'
2
+
3
+ class Ticket
4
+ def initialize hash
5
+ hash.each do |key, value|
6
+ define_singleton_method "#{key}" do
7
+ value
8
+ end
9
+ end
10
+ end
11
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,24 @@
1
+ require "cutest"
2
+ require "pry"
3
+ require_relative "../lib/sunat_books"
4
+ require_relative "fixtures/ticket"
5
+
6
+ def get_line array, object
7
+ str = ""
8
+ array.each {|f| str += object.send("#{f}") + "|"}
9
+ str
10
+ end
11
+
12
+ def random_string array
13
+ array.slice(SecureRandom.random_number(array.count - 1))
14
+ end
15
+
16
+ # to search
17
+ # Array
18
+ # tap
19
+ # chunk
20
+ # transpose
21
+ # trust
22
+ # untaint
23
+ # Hash
24
+ # dup
@@ -0,0 +1,96 @@
1
+ require_relative 'helper'
2
+
3
+ scope do
4
+ setup do
5
+ @base = PleBooks::Base.new
6
+ end
7
+
8
+ test 'book_code' do
9
+ assert @base.book_code('8.1') == '080100'
10
+ assert @base.book_code('3.1') == '030100'
11
+ end
12
+
13
+ test 'ple_book_name' do
14
+ name = @base.ple_book_name('8.1', '10201902912', 2015, 11)
15
+ assert name.length == 33
16
+
17
+ name = @base.ple_book_name('8.1', '10201902912', 2015, 11, nil, 0)
18
+ assert name.length == 33
19
+ assert name[30] == '0'
20
+
21
+ name = @base.ple_book_name('8.1', '10201902912', 2015, 11, nil, nil, 2)
22
+ assert name.length == 33
23
+ assert name[31] == '2'
24
+ end
25
+
26
+ test 'get_file' do
27
+ fields = []
28
+ 3.times { fields << random_string(String.public_methods) }
29
+
30
+ tickets = []
31
+ 3.times do
32
+ hash = {}
33
+ fields.each { |field| hash.merge!("#{field}": SecureRandom.hex(2)) }
34
+ tickets << Ticket.new(hash)
35
+ end
36
+
37
+ filename = "#{@base.path}/some_file.txt"
38
+ @base.get_file(tickets, fields, filename)
39
+
40
+ assert File.exists?(filename)
41
+
42
+ file_str = File.read(filename)
43
+ assert file_str.count("\n") == 3
44
+ assert file_str.split("\n").first == get_line(fields, tickets.first)
45
+ assert file_str.split("\n").last == get_line(fields, tickets.last)
46
+ end
47
+
48
+ scope 'buys' do
49
+
50
+ setup do
51
+ tickets = [{}]
52
+ ruc = '102392839213'
53
+ @ple_buys = PleBooks::Buys.new(ruc, tickets, 10, 2013)
54
+ end
55
+
56
+ test 'generate txt file' do
57
+ assert File.exists?(@ple_buys.file)
58
+ end
59
+
60
+ test 'tickets empty' do
61
+ ple_buys = PleBooks::Buys.new('10293827481', {}, 10, 2011)
62
+ assert File.exists?(ple_buys.file)
63
+ end
64
+
65
+ scope 'custom layout' do
66
+ test 'allow custom file for layout' do
67
+ dir = File.dirname(__FILE__)
68
+ yml = "#{dir}/fixtures/custom_layout.yml"
69
+ tickets = []
70
+ field_value = SecureRandom.hex(10)
71
+ tickets << Ticket.new(custom_field: field_value)
72
+ ple_buys = PleBooks::Buys.new('10293827481', tickets, 10, 2011,
73
+ {yml: yml})
74
+ file = ple_buys.file
75
+ assert File.exists?(file)
76
+
77
+ txt = File.read(file)
78
+ assert txt.include?(field_value)
79
+ end
80
+
81
+ test 'allow change individual field' do
82
+ tickets = []
83
+ tickets << Ticket.new(period: '20151000', operation_day: '20/10/2015')
84
+ ple_buys = PleBooks::Buys.new('10293827481', tickets, 10, 2015,
85
+ { layout: {
86
+ operation_date: 'operation_day'
87
+ }})
88
+ file = ple_buys.file
89
+ assert File.exists?(file)
90
+
91
+ txt = File.read(file)
92
+ assert txt.include?('20/10/2015')
93
+ end
94
+ end
95
+ end
96
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sunat_books
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - César Carruitero
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: prawn
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: i18n
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: cutest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: SUNAT books
70
+ email:
71
+ - cesar@mozilla.pe
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - Gemfile.lock
79
+ - Makefile
80
+ - README.mkd
81
+ - lib/books/base.rb
82
+ - lib/books/buys.rb
83
+ - lib/books/count_sum.rb
84
+ - lib/books/layouts/buys.yml
85
+ - lib/books/layouts/sales.yml
86
+ - lib/books/sales.rb
87
+ - lib/books/simplified_diary.rb
88
+ - lib/ple_books/base.rb
89
+ - lib/ple_books/book_codes.csv
90
+ - lib/ple_books/buys.rb
91
+ - lib/ple_books/layouts/buys.yml
92
+ - lib/ple_books/layouts/sales.yml
93
+ - lib/ple_books/sales.rb
94
+ - lib/sunat_books.rb
95
+ - sunat_books.gemspec
96
+ - test/fixtures/custom_layout.yml
97
+ - test/fixtures/ticket.rb
98
+ - test/helper.rb
99
+ - test/ple_books_test.rb
100
+ homepage: https://github.com/ccarruitero/books
101
+ licenses:
102
+ - MPL
103
+ metadata: {}
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 2.5.1
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: SUNAT books
124
+ test_files: []