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.
@@ -1,149 +1,97 @@
1
- require 'books/base'
2
- require 'books/count_sum'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "count_sum"
5
+ require_relative "diary_entries"
6
+ require_relative "pages_utils"
3
7
 
4
8
  module Books
5
9
  class SimplifiedDiary < Base
6
- def initialize company, tickets, view, month, year
10
+ include DiaryEntries
11
+ include PagesUtils
12
+ def initialize(company, tickets, view, month, year)
7
13
  super(page_layout: :landscape, margin: [5], page_size: "A4")
8
14
  @view = view
9
15
  @company = company
10
16
  @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) }
17
+ # @book_name = self.class.name.downcase.sub("books::", "")
18
+ # dir = File.dirname(__FILE__)
19
+ # @blayout = YAML.load_file("#{dir}/layouts/#{@book_name}.yml")
20
+ @main_title = "LIBRO DIARIO - FORMATO SIMPLIFICADO"
21
+ @counts = get_mother_counts @tickets
22
+ @total_sums = @counts.map { |count| CountSum.new(count) }
23
+
24
+ prawn_book(month, year)
25
+ end
16
26
 
27
+ def prawn_book(month, year)
17
28
  (month.to_i..12).each do |m|
18
29
  start_new_page unless m == month.to_i
19
30
  period = get_period(m, year)
20
31
 
21
- bounding_box([bounds.left + 3, bounds.top - 10], width: 815, height: 510) do
22
- book_body m, year, total_sums, 20, period
32
+ x = bounds.left + 3
33
+ y = bounds.top - 10
34
+ bounding_box([x, y], width: 815, height: 510) do
35
+ book_body m, year, 20, period
23
36
  end
24
37
  end
25
38
  end
26
39
 
27
- def book_body month, year, total_sums, max_column=nil, period=nil
28
- data = []
40
+ def book_body(month, year, max_column = nil, period = nil)
29
41
  tickets = @tickets.where(period_month: month, period_year: year)
30
42
 
31
43
  # header
32
- # counts = get_counts @tickets
33
- counts = get_mother_counts @tickets
34
- data << ['FECHA', 'OPERACIÓN', counts].flatten
44
+ data = []
45
+ initial_day = get_date(year.to_i, month.to_i, 1)
46
+ draw_table_header(tickets, @counts, @total_sums, data, initial_day)
35
47
 
36
- # body
48
+ period_date = get_date(year, month, -1)
49
+ entries_data(tickets, @counts, @total_sums, data, period_date)
37
50
 
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
51
+ book_header period, @company.ruc, @company.name, @main_title
52
+ draw_table_body(data, max_column, period)
53
+ end
58
54
 
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
55
+ def not_moviment_data(data)
56
+ data << [{ content: "SIN MOVIMIENTO EN EL PERIODO", colspan: 5 }]
57
+ end
65
58
 
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
59
+ def entries_data(tickets, counts, total_sums, data, period_date)
60
+ return not_moviment_data(data) if tickets.empty?
61
+ sales_entry(tickets, counts, total_sums, data, period_date)
62
+ buys_entry(tickets, counts, total_sums, data, period_date)
63
+ other_entry(tickets, counts, total_sums, data)
64
+ close_entry(tickets, counts, total_sums, data)
65
+ total_entry(total_sums, data)
66
+ end
82
67
 
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
68
+ def draw_table_header(tickets, counts, total_sums, data, date)
69
+ data << ["FECHA", "OPERACIÓN", counts].flatten
101
70
 
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
71
+ # body
72
+ initial_data = initial_entry(tickets, counts, total_sums)
73
+ data << [date, "ASIENTO INICIAL DEL PERIODO", initial_data].flatten
74
+ end
134
75
 
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 })
76
+ def draw_table_body(data, max_column, period)
77
+ return render_prawn_table(data) unless data.first.count > max_column
141
78
 
142
- else
79
+ pages = split_data(data, max_column)
143
80
 
144
- table(data, header: true, cell_style: {borders: [], size: 6},
145
- column_widths: { 1 => 73 })
81
+ pages.each do |page|
82
+ prawn_new_page(period) unless page.page_number.zero?
83
+ render_prawn_table(page.data)
146
84
  end
147
85
  end
86
+
87
+ def prawn_new_page(period)
88
+ start_new_page
89
+ book_header period, @company.ruc, @company.name, @main_title
90
+ end
91
+
92
+ def render_prawn_table(data)
93
+ table(data, header: true, cell_style: { borders: [], size: 6 },
94
+ column_widths: { 1 => 73 })
95
+ end
148
96
  end
149
97
  end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/all"
4
+ require_relative "count_sum"
5
+
6
+ module Utils
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" }.freeze
13
+
14
+ def formated_number(float)
15
+ number_to_currency(float, unit: "")
16
+ end
17
+
18
+ def get_date(year, month, day)
19
+ parse_day(Date.new(year.to_i, month.to_i, day))
20
+ end
21
+
22
+ def get_period(month, year)
23
+ "#{MONTHS[month.to_i].upcase} #{year}"
24
+ end
25
+
26
+ def parse_day(day)
27
+ day.strftime("%d-%m").to_s
28
+ end
29
+
30
+ def add_align(aligns, options, key)
31
+ cell_style = options[:cell_style]
32
+ aligns.map do |a|
33
+ cell_style.merge!(align: a[key][0].to_sym) unless a[key].nil?
34
+ end
35
+ end
36
+
37
+ def add_widths(column_widths, options, width)
38
+ if column_widths.empty?
39
+ options[:cell_style][:width] = width
40
+ else
41
+ options.merge!(column_widths: column_widths)
42
+ end
43
+ end
44
+
45
+ def get_column_widths(widths, key)
46
+ obj = {}
47
+ widths&.each do |w|
48
+ obj = w[key].flatten unless w[key].nil?
49
+ end
50
+ obj
51
+ end
52
+
53
+ def txt(txt)
54
+ text txt, size: 8
55
+ end
56
+
57
+ def zero
58
+ formated_number(0)
59
+ end
60
+
61
+ def field_value(ticket, field)
62
+ begin
63
+ value = ticket.send(field)
64
+ value = formated_number(value) if value.class == BigDecimal
65
+ rescue
66
+ value = ""
67
+ end
68
+ value
69
+ end
70
+
71
+ def sum_count(count_sums, count)
72
+ sum = nil
73
+ count_sums.each do |count_sum|
74
+ sum = count_sum if count_sum.count == count
75
+ end
76
+ sum
77
+ end
78
+
79
+ def order_data_row(counts, count_sums, total_sums)
80
+ data = []
81
+ counts.each_with_index do |count, i|
82
+ sum = sum_count(count_sums, count)
83
+ value = sum ? sum.total : 0
84
+ total_sums[i].add value
85
+ data << { content: formated_number(value), align: :right }
86
+ end
87
+ data
88
+ end
89
+
90
+ def get_row_sums(tickets, counts, total_sums)
91
+ # given an array of counts and tickets get sums by each count
92
+ row_counts = get_mother_counts tickets
93
+ count_sums = row_counts.map { |count| Books::CountSum.new(count) }
94
+
95
+ # get totals
96
+ tickets.each do |ticket|
97
+ count_sums.each do |count_sum|
98
+ count_sum.add get_value(ticket, count_sum.count)
99
+ end
100
+ end
101
+
102
+ # get ordered row
103
+ order_data_row(counts, count_sums, total_sums)
104
+ end
105
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+ require_relative "option_error"
5
+
6
+ module CsvBooks
7
+ class Base
8
+ attr_accessor :file
9
+
10
+ def initialize(tickets, options = {})
11
+ # options
12
+ # - layout => Array of strings used to get data for csv
13
+ # - filename
14
+ if options[:layout].nil?
15
+ raise CsvBooks::OptionError.new(msg: "Layout option is required")
16
+ end
17
+ filename = options[:filename] || "#{tmp_path}book.csv"
18
+ fields = options[:layout]
19
+ get_file(filename, fields, tickets)
20
+ end
21
+
22
+ def get_file(filename, fields, tickets)
23
+ send("file=", filename)
24
+ File.exist?(filename) ? File.delete(filename) : nil
25
+ FileUtils.touch(filename)
26
+ append_headers(filename, fields)
27
+ append_data(tickets, filename, fields)
28
+ end
29
+
30
+ def tmp_path
31
+ dir = File.dirname(__FILE__)
32
+ tmp_path = "#{dir}/tmp/"
33
+ Dir.mkdir(tmp_path) unless Dir.exist?(tmp_path)
34
+ tmp_path
35
+ end
36
+
37
+ def append_headers(filename, fields)
38
+ append_to_csv(filename, fields, "w+")
39
+ end
40
+
41
+ def append_data(tickets, filename, fields)
42
+ tickets&.each do |ticket|
43
+ data = []
44
+ fields&.each do |field|
45
+ data << field_value(ticket, field)
46
+ end
47
+ append_to_csv(filename, data, "a+")
48
+ end
49
+ end
50
+
51
+ def field_value(ticket, field)
52
+ begin
53
+ value = ticket.send(field)
54
+ rescue
55
+ value = ""
56
+ end
57
+ value
58
+ end
59
+
60
+ def append_to_csv(filename, data, mode)
61
+ return if data.nil?
62
+ CSV.open(filename, mode) do |csv|
63
+ csv << data
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CsvBooks
4
+ class OptionError < StandardError
5
+ end
6
+ end
@@ -1,19 +1,22 @@
1
- require 'csv'
1
+ # frozen_string_literal: false
2
+
3
+ require "csv"
2
4
 
3
5
  module PleBooks
4
6
  class Base
5
7
  attr_accessor :file
6
8
 
7
- def ple_book_name uid, ruc, month, year, operations_state=nil, content=nil, currency=nil
9
+ def ple_book_name(uid, ruc, month, year, *args)
8
10
  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"
11
+ code_oportunity = "00" # TODO: case for 'inventarios y balances'
12
+ operations_state = args[0] || 1 # 0, 1, 2
13
+ content = args[1] || 1 # 1 ,0
14
+ currency = args[2] || 1 # 1, 2
15
+ name = "LE#{ruc}#{year}#{month}00#{code}#{code_oportunity}"
16
+ name << "#{operations_state}#{content}#{currency}1"
14
17
  end
15
18
 
16
- def book_code uid
19
+ def book_code(uid)
17
20
  dir = File.dirname(__FILE__)
18
21
  path = "#{dir}/book_codes.csv"
19
22
  code = ""
@@ -29,32 +32,44 @@ module PleBooks
29
32
  def path
30
33
  dir = File.dirname(__FILE__)
31
34
  tmp_path = "#{dir}/tmp/"
32
- Dir.mkdir(tmp_path) unless Dir.exists?(tmp_path)
35
+ Dir.mkdir(tmp_path) unless Dir.exist?(tmp_path)
33
36
  tmp_path
34
37
  end
35
38
 
36
39
  def get_file(tickets, fields, filename)
37
- FileUtils.touch("#{filename}")
40
+ FileUtils.touch(filename.to_s)
38
41
 
39
42
  send("file=", filename)
40
43
 
41
44
  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
45
+ ticket_data = get_value(fields, ticket)
52
46
 
53
- mode = (i == 0 ? "w+" : "a+")
54
- File.open("#{filename}", mode) do |txt|
47
+ mode = (i.zero? ? "w+" : "a+")
48
+ File.open(filename.to_s, mode) do |txt|
55
49
  txt.puts(ticket_data)
56
50
  end
57
51
  end
58
52
  end
53
+
54
+ def get_value(fields, ticket)
55
+ data = ""
56
+ fields.each do |field|
57
+ begin
58
+ value = ticket.send(field)
59
+ rescue
60
+ value = ""
61
+ end
62
+ data << "#{value}|"
63
+ end
64
+ data
65
+ end
66
+
67
+ def check_layout(options, fields)
68
+ options[:layout]&.each do |key, value|
69
+ i = fields.index(key.to_s)
70
+ fields.delete(key.to_s)
71
+ fields.insert(i, value)
72
+ end
73
+ end
59
74
  end
60
75
  end
@@ -1,8 +1,10 @@
1
- require 'ple_books/base'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
2
4
 
3
5
  module PleBooks
4
6
  class Buys < Base
5
- def initialize(ruc, tickets, month, year, options={})
7
+ def initialize(ruc, tickets, month, year, options = {})
6
8
  # ruc => company's ruc in string format
7
9
  # tickets => an array of objects that respond to a layout's methods
8
10
  # month => a number that represent a month
@@ -15,19 +17,20 @@ module PleBooks
15
17
  dir = File.dirname(__FILE__)
16
18
  yml_path = options[:yml] || "#{dir}/layouts/#{book_name}.yml"
17
19
  fields = YAML.load_file(yml_path)
20
+ check_layout(options, fields)
21
+ content = !tickets.empty? ? 1 : 0
22
+ name = ple_book_name("8.1", ruc, month, year, nil, content)
18
23
 
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"
24
+ filename = "#{path}#{name}.txt"
30
25
  get_file(tickets, fields, filename)
31
26
  end
27
+
28
+ def insert_layout_fields(options, fields)
29
+ options[:layout].each do |key, value|
30
+ i = fields.index(key.to_s)
31
+ fields.delete(key.to_s)
32
+ fields.insert(i, value)
33
+ end
34
+ end
32
35
  end
33
36
  end
@@ -1,8 +1,8 @@
1
- - period # YYYYMM00
1
+ - period # YYYYMMDD
2
2
  - cuo # Código Unico de Operación, software (max 40)
3
3
  - correlative # 2 ..10
4
- - operation_date # day # 'dd/mm/yyyy'
5
- - pay_date # day # 'dd/mm/yyyy'
4
+ - operation_date # 'dd/mm/yyyy'
5
+ - pay_date # 'dd/mm/yyyy'
6
6
  - document_type # 2
7
7
  - document_serial # max 20
8
8
  - dua_year_emition
@@ -22,4 +22,4 @@
22
22
  - original_document_number
23
23
  - exchange_rate_error
24
24
  - payment_way
25
- - anotation_state
25
+ - anotation_oportunity
@@ -1,13 +1,19 @@
1
- require 'ple_books/base'
1
+ # frozen_string_literal: true
2
+
3
+ require "ple_books/base"
2
4
 
3
5
  module PleBooks
4
6
  class Sales < Base
5
- def initialize(ruc, tickets, month, year)
7
+ def initialize(ruc, tickets, month, year, options = {})
6
8
  book_name = self.class.name.downcase.sub("plebooks::", "")
7
9
  dir = File.dirname(__FILE__)
8
- fields = YAML.load_file("#{dir}/layouts/#{book_name}.yml")
10
+ yml_path = options[:yml] || "#{dir}/layouts/#{book_name}.yml"
11
+ fields = YAML.load_file(yml_path)
12
+ check_layout(options, fields)
13
+ content = !tickets.empty? ? 1 : 0
9
14
 
10
- @filename = "#{path}#{ple_book_name('14.2', ruc, month, year)}.txt"
15
+ name = ple_book_name("14.2", ruc, month, year, nil, content)
16
+ @filename = "#{path}#{name}.txt"
11
17
  get_file(tickets, fields, @filename)
12
18
  end
13
19
  end
data/lib/sunat_books.rb CHANGED
@@ -1,4 +1,8 @@
1
- require 'books/buys'
2
- require 'books/sales'
3
- require 'books/simplified_diary'
4
- require 'ple_books/buys'
1
+ # frozen_string_literal: false
2
+
3
+ require_relative "books/buys"
4
+ require_relative "books/sales"
5
+ require_relative "books/simplified_diary"
6
+ require_relative "ple_books/buys"
7
+ require_relative "ple_books/sales"
8
+ require_relative "csv_books/base"
data/sunat_books.gemspec CHANGED
@@ -1,18 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = "sunat_books"
3
- s.version = "0.0.1"
5
+ s.version = "0.0.2"
4
6
  s.summary = "SUNAT books"
5
7
  s.description = s.summary
6
8
  s.authors = ["César Carruitero"]
7
9
  s.email = ["cesar@mozilla.pe"]
8
- s.homepage = "https://github.com/ccarruitero/books"
10
+ s.homepage = "https://github.com/ccarruitero/sunat_books"
9
11
  s.license = "MPL"
10
12
 
11
13
  s.files = `git ls-files`.split("\n")
12
14
 
13
- s.add_runtime_dependency "prawn"
14
- s.add_runtime_dependency "i18n"
15
- s.add_runtime_dependency "activesupport"
15
+ s.add_runtime_dependency("prawn", "~> 2.0")
16
+ s.add_runtime_dependency("prawn-table", "~> 0.2")
17
+ s.add_runtime_dependency("i18n", "~> 0.7")
18
+ s.add_runtime_dependency("activesupport", "> 4.1")
16
19
 
17
- s.add_development_dependency "cutest"
20
+ s.add_development_dependency("cutest", "~> 1.2")
21
+ s.add_development_dependency("pry", "~> 0.10")
22
+ s.add_development_dependency("rubocop", "~> 0.48")
23
+ s.add_development_dependency("pdf-inspector", "~> 1.2.0")
24
+ s.add_development_dependency("faker", "~> 1.7")
18
25
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../helper"
4
+
5
+ test "#sub_head_table return a table object" do
6
+ end