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 +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: []
|