sunat_books 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +9 -0
- data/Gemfile +2 -4
- data/Gemfile.lock +51 -16
- data/Makefile +2 -1
- data/README.mkd +8 -6
- data/lib/books/base.rb +70 -150
- data/lib/books/buys.rb +34 -82
- data/lib/books/count_sum.rb +4 -2
- data/lib/books/diary_entries.rb +112 -0
- data/lib/books/layouts/sales.yml +2 -2
- data/lib/books/locale.rb +6 -0
- data/lib/books/locales/es.yml +65 -0
- data/lib/books/page.rb +44 -0
- data/lib/books/pages_utils.rb +85 -0
- data/lib/books/sales.rb +40 -81
- data/lib/books/simplified_diary.rb +65 -117
- data/lib/books/utils.rb +105 -0
- data/lib/csv_books/base.rb +67 -0
- data/lib/csv_books/option_error.rb +6 -0
- data/lib/ple_books/base.rb +37 -22
- data/lib/ple_books/buys.rb +16 -13
- data/lib/ple_books/layouts/buys.yml +3 -3
- data/lib/ple_books/layouts/sales.yml +1 -1
- data/lib/ple_books/sales.rb +10 -4
- data/lib/sunat_books.rb +8 -4
- data/sunat_books.gemspec +13 -6
- data/test/books/base_test.rb +6 -0
- data/test/books/buys_test.rb +57 -0
- data/test/books/page_test.rb +24 -0
- data/test/books/pages_utils_test.rb +78 -0
- data/test/books/utils_test.rb +42 -0
- data/test/csv_books/base_test.rb +43 -0
- data/test/fixtures/base.rb +11 -0
- data/test/fixtures/company.rb +5 -0
- data/test/fixtures/ticket.rb +4 -9
- data/test/helper.rb +11 -13
- data/test/ple_books/buys_test.rb +49 -0
- data/test/ple_books_test.rb +34 -83
- metadata +109 -20
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiaryEntries
|
4
|
+
def initial_entry(tickets, counts, total_sums)
|
5
|
+
initial = tickets.where(operation_type: "inicial")
|
6
|
+
if !initial.empty?
|
7
|
+
initial_data = get_row_sums(initial, counts, total_sums)
|
8
|
+
else
|
9
|
+
initial_data = []
|
10
|
+
total_sums.map do |sum|
|
11
|
+
initial_data << { content: formated_number(sum.total), align: :right }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
initial_data
|
15
|
+
end
|
16
|
+
|
17
|
+
def buys_entry(tickets, counts, total_sums, data, period_date)
|
18
|
+
buys = tickets.where(operation_type: "compras")
|
19
|
+
title = "COMPRAS DEL PERIODO"
|
20
|
+
return unless buys.count.positive?
|
21
|
+
# buys entry
|
22
|
+
buys_sum = get_row_sums(buys, counts, total_sums)
|
23
|
+
data << [period_date, title, buys_sum].flatten
|
24
|
+
end
|
25
|
+
|
26
|
+
def sales_entry(tickets, counts, total_sums, data, period_date)
|
27
|
+
sales = tickets.where(operation_type: "ventas")
|
28
|
+
title = "VENTAS DEL PERIODO"
|
29
|
+
return unless sales.count.positive?
|
30
|
+
sales_sum = get_row_sums(sales, counts, total_sums)
|
31
|
+
data << [period_date, title, sales_sum].flatten
|
32
|
+
end
|
33
|
+
|
34
|
+
def other_entry(tickets, counts, total_sums, data)
|
35
|
+
# other entries
|
36
|
+
others = tickets.where(operation_type: "otros")
|
37
|
+
# others_row = get_row_sums(others, counts, total_sums)
|
38
|
+
others&.each do |ticket|
|
39
|
+
ticket_data = []
|
40
|
+
counts.each_with_index do |count, i|
|
41
|
+
value = mother_count?(count, ticket) ? get_value(ticket, count) : 0
|
42
|
+
increase_value(ticket_data, total_sums, i, value)
|
43
|
+
end
|
44
|
+
ref = ticket.reference
|
45
|
+
data << [parse_day(ticket.operation_date), ref, ticket_data].flatten
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def close_entry(tickets, counts, total_sums, data)
|
50
|
+
close = tickets.where(operation_type: "cierre")
|
51
|
+
close.each do |ticket|
|
52
|
+
ticket_data = []
|
53
|
+
counts.each_with_index do |count, i|
|
54
|
+
value = mother_count?(count, ticket) ? get_value(ticket, count) : 0
|
55
|
+
increase_value(ticket_data, total_sums, i, value)
|
56
|
+
end
|
57
|
+
ref = ticket.reference
|
58
|
+
data << [parse_day(ticket.operation_date), ref, ticket_data].flatten
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def total_entry(total_sums, data)
|
63
|
+
# totals
|
64
|
+
total_data = []
|
65
|
+
total_sums.map do |sum|
|
66
|
+
total_data << { content: formated_number(sum.total), align: :right }
|
67
|
+
end
|
68
|
+
data << [{ content: "TOTALES", colspan: 2 }, total_data].flatten
|
69
|
+
end
|
70
|
+
|
71
|
+
def mother_count?(count, ticket)
|
72
|
+
ticket.uniq_mother_counts.include?(count)
|
73
|
+
end
|
74
|
+
|
75
|
+
def calculate_totals(tickets, count_sums)
|
76
|
+
# get totals
|
77
|
+
tickets.each do |ticket|
|
78
|
+
count_sums.each do |count_sum|
|
79
|
+
count_sum.add get_value(ticket, count_sum.count)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def current_sum_count(count_sums, count)
|
85
|
+
sum_count = nil
|
86
|
+
count_sums.each do |count_sum|
|
87
|
+
sum_count = count_sum if count_sum.count == count
|
88
|
+
end
|
89
|
+
sum_count
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_row_sums(tickets, counts, total_sums)
|
93
|
+
# given an array of counts and tickets get sums by each count
|
94
|
+
row_counts = get_mother_counts tickets
|
95
|
+
count_sums = row_counts.map { |count| Books::CountSum.new(count) }
|
96
|
+
|
97
|
+
calculate_totals(tickets, count_sums)
|
98
|
+
# get ordered row
|
99
|
+
row_data = []
|
100
|
+
counts.each_with_index do |count, i|
|
101
|
+
sum_count = current_sum_count(count_sums, count)
|
102
|
+
value = sum_count ? sum_count.total : 0
|
103
|
+
increase_value(row_data, total_sums, i, value)
|
104
|
+
end
|
105
|
+
row_data
|
106
|
+
end
|
107
|
+
|
108
|
+
def increase_value(row_data, total_sums, i, value)
|
109
|
+
total_sums[i].add value
|
110
|
+
row_data << { content: formated_number(value), align: :right }
|
111
|
+
end
|
112
|
+
end
|
data/lib/books/layouts/sales.yml
CHANGED
@@ -11,7 +11,7 @@ headers:
|
|
11
11
|
- client_document_number
|
12
12
|
- client_name
|
13
13
|
- export_value
|
14
|
-
- taxable_bi
|
14
|
+
- taxable_bi
|
15
15
|
- sale_non_taxable:
|
16
16
|
- exo
|
17
17
|
- inaf
|
@@ -21,7 +21,7 @@ headers:
|
|
21
21
|
- total_operation_sales
|
22
22
|
- exchange_rate
|
23
23
|
- credit_origina_document:
|
24
|
-
- credit_original_document_date
|
24
|
+
- credit_original_document_date
|
25
25
|
- credit_original_document_type
|
26
26
|
- credit_original_document_serial
|
27
27
|
- credit_original_document_number
|
data/lib/books/locale.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
es:
|
2
|
+
books:
|
3
|
+
buys:
|
4
|
+
correlative: "Nro"
|
5
|
+
operation_date: "Fecha de Emisión"
|
6
|
+
pay_date: "Fecha de Venc"
|
7
|
+
document: "Documento"
|
8
|
+
doc_type: "T"
|
9
|
+
document_serial: "Serie"
|
10
|
+
year_emition: "AÑO DUA DSI"
|
11
|
+
document_number: "N° documen"
|
12
|
+
supplier: "Proveedor"
|
13
|
+
supplier_document_type: "t"
|
14
|
+
supplier_document_number: "N° documen"
|
15
|
+
supplier_name: "Nombre o razón social"
|
16
|
+
taxable_to_taxable_export: "adquisiciones grav. dest. a oper. gravadas y/o de exportac."
|
17
|
+
taxable_to_taxable_export_bi: "bi"
|
18
|
+
taxable_to_taxable_export_igv: "igv"
|
19
|
+
taxable_to_taxable_export_non_taxable: "adquisiciones gravadas dest. a oper. grav. y/o exportac. y a oper. no gravadas"
|
20
|
+
taxable_to_taxable_export_non_taxable_bi: "bi"
|
21
|
+
taxable_to_taxable_export_non_taxable_igv: "igv"
|
22
|
+
taxable_to_non_taxable: "adquisiciones gravadas destinadas a operaciones no gravadas"
|
23
|
+
taxable_to_non_taxable_bi: "bi"
|
24
|
+
taxable_to_non_taxable_igv: "igv"
|
25
|
+
non_taxable: "adquisiciones no gravadas"
|
26
|
+
isc: "isc"
|
27
|
+
other_taxs: "otros tributos y cargos"
|
28
|
+
total_operation_buys: "importe total"
|
29
|
+
foreign_pay_document_number: "n° comprobante pago emitido por no domiciliado"
|
30
|
+
detraction: "detracción"
|
31
|
+
detraction_number: "número"
|
32
|
+
detraction_date: "fech emis"
|
33
|
+
exchange_rate: "tipo de cambio"
|
34
|
+
debit_original_document: "referencia del comprobante de pago que se modifica"
|
35
|
+
debit_original_document_date: "Fecha"
|
36
|
+
debit_original_document_type: "t"
|
37
|
+
debit_original_document_serial: "serie"
|
38
|
+
debit_original_document_number: "n° doc"
|
39
|
+
sales:
|
40
|
+
correlative: "nro"
|
41
|
+
operation_date: "Fecha de Emisión"
|
42
|
+
pay_date: "Fecha de Venc"
|
43
|
+
document: "Documento"
|
44
|
+
doc_type: "T"
|
45
|
+
document_serial: "Serie"
|
46
|
+
document_number: "N° documen"
|
47
|
+
client: "Cliente"
|
48
|
+
client_document_type: "t"
|
49
|
+
client_document_number: "N° documen"
|
50
|
+
client_name: "Nombre o razón social"
|
51
|
+
export_value: "Valor exportac"
|
52
|
+
taxable_bi: "BI operac gravadas"
|
53
|
+
sale_non_taxable: "operacion. exoneradas o inafectas"
|
54
|
+
exo: "Exo"
|
55
|
+
inaf: "Inaf"
|
56
|
+
isc: "ISC"
|
57
|
+
igv: "IGV"
|
58
|
+
other_taxs: "Otros tributos"
|
59
|
+
total_operation_sales: "importe total"
|
60
|
+
exchange_rate: "tipo de cambio"
|
61
|
+
credit_origina_document: "referencia de documento original que se modifica"
|
62
|
+
credit_original_document_date: "Fec"
|
63
|
+
credit_original_document_type: "t"
|
64
|
+
credit_original_document_serial: "serie"
|
65
|
+
credit_original_document_number: "n° doc"
|
data/lib/books/page.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Books
|
6
|
+
class Page < Base
|
7
|
+
attr_accessor :length, :bi_sum, :igv_sum, :total_sum, :non_taxable, :data
|
8
|
+
|
9
|
+
def initialize(page_number, length)
|
10
|
+
@page_number = page_number
|
11
|
+
@length = length
|
12
|
+
@bi_sum = BigDecimal(0)
|
13
|
+
@igv_sum = BigDecimal(0)
|
14
|
+
@total_sum = BigDecimal(0)
|
15
|
+
@non_taxable = BigDecimal(0)
|
16
|
+
@data = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def update_data_buys(ticket)
|
20
|
+
@bi_sum += ticket.taxable_to_taxable_export_bi.round(2)
|
21
|
+
@igv_sum += ticket.taxable_to_taxable_export_igv.round(2)
|
22
|
+
@total_sum += ticket.total_operation_buys.round(2)
|
23
|
+
@non_taxable += ticket.non_taxable unless ticket.non_taxable.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_data_sales(ticket)
|
27
|
+
@bi_sum += ticket.taxable_bi.round(2)
|
28
|
+
@igv_sum += ticket.igv.round(2)
|
29
|
+
@total_sum += ticket.total_operation_sales.round(2)
|
30
|
+
end
|
31
|
+
|
32
|
+
def update_fields(fields = nil, source = nil)
|
33
|
+
# update fields from a given source
|
34
|
+
return if source.nil?
|
35
|
+
fields&.each do |field|
|
36
|
+
begin
|
37
|
+
send("#{field}=", source.send(field))
|
38
|
+
rescue
|
39
|
+
return nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "page"
|
4
|
+
|
5
|
+
module PagesUtils
|
6
|
+
def page_not_full(last_page, pages, page_max, &block)
|
7
|
+
if last_page.length < page_max
|
8
|
+
last_page.length += 1
|
9
|
+
last_page
|
10
|
+
else
|
11
|
+
yield if block
|
12
|
+
new_page = setup_new_page(pages, last_page, 2)
|
13
|
+
new_page
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup_pages(pages, length, page_max, index = 1)
|
18
|
+
pages_num = (length / page_max.to_f).ceil
|
19
|
+
last_index = index.zero? ? pages_num - 1 : pages_num
|
20
|
+
(index..last_index).each do |i|
|
21
|
+
pages[i] = Books::Page.new(i, 0)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup_new_page(pages, last_page, length)
|
26
|
+
return if last_page.page_number == pages.count
|
27
|
+
new_page = pages[last_page.page_number + 1]
|
28
|
+
fields = %w[bi_sum igv_sum total_sum non_taxable]
|
29
|
+
new_page.update_fields(fields, last_page)
|
30
|
+
new_page.length += length
|
31
|
+
new_page
|
32
|
+
end
|
33
|
+
|
34
|
+
def page_index(i, page_max)
|
35
|
+
i.zero? ? 1 : (i / page_max.to_f).ceil
|
36
|
+
end
|
37
|
+
|
38
|
+
def not_moviment_page(data)
|
39
|
+
data << [content: "SIN MOVIMIENTO EN EL PERIODO", colspan: 5]
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup_final_row_data(page, ticket, data)
|
43
|
+
if page.length == @page_max && @tickets.last != ticket
|
44
|
+
data << final_row("VAN", page)
|
45
|
+
elsif @tickets.last == ticket
|
46
|
+
data << final_row("TOTAL", page)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def row_data(data, widths, aligns, fields, operation)
|
51
|
+
@tickets.each_with_index do |ticket, i|
|
52
|
+
last_page = @pages[page_index(i, @page_max)]
|
53
|
+
page = page_not_full(last_page, @pages, @page_max) do
|
54
|
+
data << final_row("VIENEN", last_page)
|
55
|
+
end
|
56
|
+
data << table_body(fields, ticket, widths, aligns)
|
57
|
+
page.send("update_data_#{operation}", ticket)
|
58
|
+
setup_final_row_data(page, ticket, data)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# for diary
|
63
|
+
def split_data(data, max_column)
|
64
|
+
# split rows data in pages according max_column
|
65
|
+
pages = []
|
66
|
+
setup_pages(pages, data.first.count, max_column, 0)
|
67
|
+
data&.each_with_index do |row, i|
|
68
|
+
if i == data.length - 1
|
69
|
+
setup_row_pages(pages, row, max_column - 1, 1)
|
70
|
+
else
|
71
|
+
setup_row_pages(pages, row, max_column)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
pages
|
75
|
+
end
|
76
|
+
|
77
|
+
def setup_row_pages(pages, row, max_column, first_rows = 2)
|
78
|
+
initial_rows = row.first(first_rows)
|
79
|
+
batches_length = max_column - first_rows
|
80
|
+
left_data = row[first_rows..row.length].in_groups_of(batches_length, false)
|
81
|
+
pages.each_with_index do |page, i|
|
82
|
+
page.data << (initial_rows + left_data[i])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/books/sales.rb
CHANGED
@@ -1,114 +1,73 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require_relative "pages_utils"
|
2
5
|
|
3
6
|
module Books
|
4
7
|
class Sales < Base
|
8
|
+
include PagesUtils
|
9
|
+
|
5
10
|
def initialize(company, tickets, view, month, year)
|
11
|
+
# company => an object that respond to ruc and name methods
|
12
|
+
# tickets => an array of objects that respond to a layout's methods
|
13
|
+
# view => a view context
|
14
|
+
# month => a number that represent a month
|
15
|
+
# year => a number that represent a year
|
6
16
|
super(page_layout: :landscape, margin: [5], page_size: "A4")
|
7
17
|
@view = view
|
8
18
|
@company = company
|
9
19
|
@period = get_period(month, year)
|
10
|
-
@pages = {}
|
11
20
|
@tickets = tickets
|
12
21
|
@book_name = self.class.name.downcase.sub("books::", "")
|
13
22
|
dir = File.dirname(__FILE__)
|
14
23
|
@blayout = YAML.load_file("#{dir}/layouts/#{@book_name}.yml")
|
15
24
|
@page_max = 29
|
16
25
|
|
17
|
-
|
18
|
-
|
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
|
26
|
+
prawn_book
|
27
|
+
end
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
def prawn_book
|
30
|
+
prawn_header "REGISTRO DE VENTAS", @period, @company
|
31
|
+
@pages = []
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
33
|
+
bounding_box([bounds.left + 3, bounds.top - 45], width: 800,
|
34
|
+
height: 530) do
|
35
|
+
setup_pages(@pages, @tickets.length, @page_max)
|
36
|
+
book_body
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
40
|
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
41
|
move_down 5
|
51
|
-
fields = @blayout["headers"]
|
52
|
-
widths = @blayout["widths"]
|
53
|
-
aligns = @blayout["align"]
|
54
42
|
data = []
|
43
|
+
fields = @blayout["headers"]
|
55
44
|
data << table_head(fields, @book_name, @blayout)
|
56
45
|
|
57
|
-
|
58
|
-
|
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
|
46
|
+
if @tickets.length.positive?
|
47
|
+
row_data(data, @blayout["widths"], @blayout["align"], fields, "sales")
|
90
48
|
else
|
91
|
-
data
|
92
|
-
@pages[n] = {}
|
93
|
-
page = @pages[n]
|
94
|
-
page[:bi_sum] = zero
|
95
|
-
page[:igv_sum] = zero
|
96
|
-
page[:total_sum] = zero
|
49
|
+
not_moviment_page(data)
|
97
50
|
end
|
98
51
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
52
|
+
render_prawn_table(data)
|
53
|
+
end
|
54
|
+
|
55
|
+
def render_prawn_table(data)
|
56
|
+
widths_columns = { 0 => 22, 1 => 35, 2 => 30, 5 => 27, 6 => 37, 8 => 20,
|
57
|
+
9 => 33, 10 => 27, 11 => 35, 12 => 29 }
|
58
|
+
|
59
|
+
table(data, header: true,
|
60
|
+
cell_style: { borders: [], size: 5, align: :right },
|
61
|
+
column_widths: widths_columns) do
|
62
|
+
row(0).borders = %i[bottom top]
|
104
63
|
end
|
105
64
|
end
|
106
65
|
|
107
|
-
def final_row
|
108
|
-
[
|
109
|
-
|
110
|
-
|
111
|
-
|
66
|
+
def final_row(foot_line_text, page)
|
67
|
+
[{ content: foot_line_text, colspan: 5 }, zero,
|
68
|
+
formated_number(page.bi_sum), make_sub_table([zero, zero], 22), zero,
|
69
|
+
formated_number(page.igv_sum), zero,
|
70
|
+
formated_number(page.total_sum)]
|
112
71
|
end
|
113
72
|
end
|
114
73
|
end
|