sunat_books 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []