sunat_books 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +48 -0
- data/Makefile +7 -0
- data/README.mkd +37 -0
- data/lib/books/base.rb +212 -0
- data/lib/books/buys.rb +120 -0
- data/lib/books/count_sum.rb +20 -0
- data/lib/books/layouts/buys.yml +52 -0
- data/lib/books/layouts/sales.yml +36 -0
- data/lib/books/sales.rb +114 -0
- data/lib/books/simplified_diary.rb +149 -0
- data/lib/ple_books/base.rb +60 -0
- data/lib/ple_books/book_codes.csv +48 -0
- data/lib/ple_books/buys.rb +33 -0
- data/lib/ple_books/layouts/buys.yml +34 -0
- data/lib/ple_books/layouts/sales.yml +25 -0
- data/lib/ple_books/sales.rb +14 -0
- data/lib/sunat_books.rb +4 -0
- data/sunat_books.gemspec +18 -0
- data/test/fixtures/custom_layout.yml +2 -0
- data/test/fixtures/ticket.rb +11 -0
- data/test/helper.rb +24 -0
- data/test/ple_books_test.rb +96 -0
- metadata +124 -0
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
data/Gemfile
ADDED
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
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]
|
data/lib/books/sales.rb
ADDED
@@ -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
|
data/lib/sunat_books.rb
ADDED
data/sunat_books.gemspec
ADDED
@@ -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
|
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: []
|