sunat_books 0.0.2 → 0.0.3

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +2 -5
  5. data/README.mkd +9 -3
  6. data/lib/sunat_books.rb +6 -6
  7. data/lib/sunat_books/common_utils.rb +9 -0
  8. data/lib/sunat_books/csv/base.rb +63 -0
  9. data/lib/sunat_books/csv/option_error.rb +8 -0
  10. data/lib/sunat_books/pdf/base.rb +134 -0
  11. data/lib/sunat_books/pdf/buys.rb +36 -0
  12. data/lib/sunat_books/pdf/count_sum.rb +24 -0
  13. data/lib/{books → sunat_books/pdf}/diary_entries.rb +1 -3
  14. data/lib/{books → sunat_books/pdf}/layouts/buys.yml +0 -0
  15. data/lib/{books → sunat_books/pdf}/layouts/sales.yml +0 -0
  16. data/lib/{books → sunat_books/pdf}/locale.rb +0 -0
  17. data/lib/{books → sunat_books/pdf}/locales/es.yml +0 -0
  18. data/lib/sunat_books/pdf/page.rb +48 -0
  19. data/lib/{books → sunat_books/pdf}/pages_utils.rb +1 -1
  20. data/lib/sunat_books/pdf/sales.rb +35 -0
  21. data/lib/sunat_books/pdf/simplified_diary.rb +94 -0
  22. data/lib/sunat_books/pdf/trading_book.rb +50 -0
  23. data/lib/{books → sunat_books/pdf}/utils.rb +4 -6
  24. data/lib/sunat_books/ple/base.rb +76 -0
  25. data/lib/sunat_books/ple/buys.rb +38 -0
  26. data/lib/{ple_books → sunat_books/ple}/layouts/buys.yml +0 -0
  27. data/lib/{ple_books → sunat_books/ple}/layouts/sales.yml +0 -0
  28. data/lib/sunat_books/ple/sales.rb +22 -0
  29. data/sunat_books.gemspec +2 -2
  30. data/test/{csv_books → csv}/base_test.rb +8 -5
  31. data/test/{books → pdf}/base_test.rb +0 -0
  32. data/test/pdf/buys_test.rb +27 -0
  33. data/test/{books → pdf}/page_test.rb +4 -4
  34. data/test/{books → pdf}/pages_utils_test.rb +32 -2
  35. data/test/pdf/sales_test.rb +15 -0
  36. data/test/{books → pdf}/utils_test.rb +7 -1
  37. data/test/{ple_books_test.rb → ple/base_test.rb} +2 -2
  38. data/test/{ple_books → ple}/buys_test.rb +8 -8
  39. metadata +38 -35
  40. data/Gemfile.lock +0 -83
  41. data/lib/books/base.rb +0 -132
  42. data/lib/books/buys.rb +0 -72
  43. data/lib/books/count_sum.rb +0 -22
  44. data/lib/books/page.rb +0 -44
  45. data/lib/books/sales.rb +0 -73
  46. data/lib/books/simplified_diary.rb +0 -97
  47. data/lib/csv_books/base.rb +0 -67
  48. data/lib/csv_books/option_error.rb +0 -6
  49. data/lib/ple_books/base.rb +0 -75
  50. data/lib/ple_books/buys.rb +0 -36
  51. data/lib/ple_books/sales.rb +0 -20
  52. data/test/books/buys_test.rb +0 -57
@@ -18,7 +18,7 @@ module PagesUtils
18
18
  pages_num = (length / page_max.to_f).ceil
19
19
  last_index = index.zero? ? pages_num - 1 : pages_num
20
20
  (index..last_index).each do |i|
21
- pages[i] = Books::Page.new(i, 0)
21
+ pages[i] = SunatBooks::Pdf::Page.new(i, 0)
22
22
  end
23
23
  end
24
24
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "trading_book"
4
+ require_relative "pages_utils"
5
+
6
+ module SunatBooks
7
+ module Pdf
8
+ class Sales < TradingBook
9
+ include PagesUtils
10
+
11
+ def initialize(company, tickets, month, year)
12
+ super
13
+ prawn_book("REGISTRO DE VENTAS", 29)
14
+ end
15
+
16
+ def render_prawn_table(data)
17
+ widths_columns = { 0 => 22, 1 => 35, 2 => 30, 5 => 27, 6 => 37, 8 => 20,
18
+ 9 => 33, 10 => 27, 11 => 35, 12 => 29 }
19
+
20
+ table(data, header: true,
21
+ cell_style: { borders: [], size: 5, align: :right },
22
+ column_widths: widths_columns) do
23
+ row(0).borders = %i[bottom top]
24
+ end
25
+ end
26
+
27
+ def final_row(foot_line_text, page)
28
+ [{ content: foot_line_text, colspan: 5 }, zero,
29
+ formated_number(page.bi_sum), make_sub_table([zero, zero], 22), zero,
30
+ formated_number(page.igv_sum), zero,
31
+ formated_number(page.total_sum)]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,94 @@
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"
7
+
8
+ module SunatBooks
9
+ module Pdf
10
+ class SimplifiedDiary < Base
11
+ include DiaryEntries
12
+ include PagesUtils
13
+ def initialize(company, tickets, month, year)
14
+ super(page_layout: :landscape, margin: [5], page_size: "A4")
15
+ @company = company
16
+ @tickets = tickets
17
+ @main_title = "LIBRO DIARIO - FORMATO SIMPLIFICADO"
18
+ @counts = get_mother_counts @tickets
19
+ @total_sums = @counts.map { |count| CountSum.new(count) }
20
+
21
+ prawn_book(month, year)
22
+ end
23
+
24
+ def prawn_book(month, year)
25
+ (month.to_i..12).each do |m|
26
+ start_new_page unless m == month.to_i
27
+ period = get_period(m, year)
28
+
29
+ x = bounds.left + 3
30
+ y = bounds.top - 10
31
+ bounding_box([x, y], width: 815, height: 510) do
32
+ book_body m, year, 20, period
33
+ end
34
+ end
35
+ end
36
+
37
+ def book_body(month, year, max_column = nil, period = nil)
38
+ tickets = @tickets.where(period_month: month, period_year: year)
39
+
40
+ # header
41
+ data = []
42
+ initial_day = get_date(year.to_i, month.to_i, 1)
43
+ draw_table_header(tickets, @counts, @total_sums, data, initial_day)
44
+
45
+ period_date = get_date(year, month, -1)
46
+ entries_data(tickets, @counts, @total_sums, data, period_date)
47
+
48
+ book_header period, @company.ruc, @company.name, @main_title
49
+ draw_table_body(data, max_column, period)
50
+ end
51
+
52
+ def not_moviment_data(data)
53
+ data << [{ content: "SIN MOVIMIENTO EN EL PERIODO", colspan: 5 }]
54
+ end
55
+
56
+ def entries_data(tickets, counts, total_sums, data, period_date)
57
+ return not_moviment_data(data) if tickets.empty?
58
+ sales_entry(tickets, counts, total_sums, data, period_date)
59
+ buys_entry(tickets, counts, total_sums, data, period_date)
60
+ other_entry(tickets, counts, total_sums, data)
61
+ close_entry(tickets, counts, total_sums, data)
62
+ total_entry(total_sums, data)
63
+ end
64
+
65
+ def draw_table_header(tickets, counts, total_sums, data, date)
66
+ data << ["FECHA", "OPERACIÓN", counts].flatten
67
+
68
+ initial_data = initial_entry(tickets, counts, total_sums)
69
+ data << [date, "ASIENTO INICIAL DEL PERIODO", initial_data].flatten
70
+ end
71
+
72
+ def draw_table_body(data, max_column, period)
73
+ return render_prawn_table(data) unless data.first.count > max_column
74
+
75
+ pages = split_data(data, max_column)
76
+
77
+ pages.each do |page|
78
+ prawn_new_page(period) unless page.page_number.zero?
79
+ render_prawn_table(page.data)
80
+ end
81
+ end
82
+
83
+ def prawn_new_page(period)
84
+ start_new_page
85
+ book_header period, @company.ruc, @company.name, @main_title
86
+ end
87
+
88
+ def render_prawn_table(data)
89
+ table(data, header: true, cell_style: { borders: [], size: 6 },
90
+ column_widths: { 1 => 73 })
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module SunatBooks
6
+ module Pdf
7
+ class TradingBook < Base
8
+ def initialize(company, tickets, month, year)
9
+ # company => an object that respond to ruc and name methods
10
+ # tickets => an array of objects that respond to a layout's methods
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
+ @company = company
15
+ @period = get_period(month, year)
16
+ @tickets = tickets
17
+ @book_name = self.class.name.downcase.sub("sunatbooks::pdf::", "")
18
+ dir = File.dirname(__FILE__)
19
+ @blayout = YAML.load_file("#{dir}/layouts/#{@book_name}.yml")
20
+ end
21
+
22
+ def prawn_book(title, page_max)
23
+ prawn_header title, @period, @company
24
+ @pages = []
25
+ @page_max = page_max
26
+
27
+ bounding_box([bounds.left + 3, bounds.top - 45], width: 800,
28
+ height: 530) do
29
+ setup_pages(@pages, @tickets.length, @page_max)
30
+ move_down 5
31
+ book_body
32
+ end
33
+ end
34
+
35
+ def book_body
36
+ data = []
37
+ fields = @blayout["headers"]
38
+ data << table_head(fields, @book_name, @blayout)
39
+
40
+ if @tickets.length.positive?
41
+ row_data(data, @blayout["widths"], @blayout["align"], fields,
42
+ @book_name)
43
+ else
44
+ not_moviment_page(data)
45
+ end
46
+ render_prawn_table(data)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -2,9 +2,11 @@
2
2
 
3
3
  require "active_support/all"
4
4
  require_relative "count_sum"
5
+ require_relative "../common_utils"
5
6
 
6
7
  module Utils
7
8
  include ActiveSupport::NumberHelper
9
+ include SunatBooks::CommonUtils
8
10
 
9
11
  MONTHS = { 1 => "Enero", 2 => "Febrero", 3 => "marzo", 4 => "abril",
10
12
  5 => "mayo", 6 => "junio", 7 => "julio", 8 => "agosto",
@@ -59,12 +61,8 @@ module Utils
59
61
  end
60
62
 
61
63
  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
64
+ value = available_value?(ticket, field)
65
+ value = formated_number(value) if value.class == BigDecimal
68
66
  value
69
67
  end
70
68
 
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: false
2
+
3
+ require "csv"
4
+ require_relative "../common_utils"
5
+
6
+ module SunatBooks
7
+ module Ple
8
+ class Base
9
+ include SunatBooks::CommonUtils
10
+
11
+ attr_accessor :file
12
+
13
+ def ple_book_name(uid, ruc, month, year, *args)
14
+ code = book_code(uid)
15
+ code_oportunity = "00" # TODO: case for 'inventarios y balances'
16
+ operations_state = args[0] || 1 # 0, 1, 2
17
+ content = args[1] || 1 # 1 ,0
18
+ currency = args[2] || 1 # 1, 2
19
+ name = "LE#{ruc}#{year}#{month}00#{code}#{code_oportunity}"
20
+ name << "#{operations_state}#{content}#{currency}1"
21
+ end
22
+
23
+ def book_code(uid)
24
+ dir = File.dirname(__FILE__)
25
+ path = "#{dir}/book_codes.csv"
26
+ code = ""
27
+ CSV.foreach(path) do |row|
28
+ if row[0] == uid
29
+ code = row[2]
30
+ break
31
+ end
32
+ end
33
+ code
34
+ end
35
+
36
+ def path
37
+ dir = File.dirname(__FILE__)
38
+ tmp_path = "#{dir}/tmp/"
39
+ Dir.mkdir(tmp_path) unless Dir.exist?(tmp_path)
40
+ tmp_path
41
+ end
42
+
43
+ def get_file(tickets, fields, filename)
44
+ FileUtils.touch(filename.to_s)
45
+
46
+ send("file=", filename)
47
+
48
+ tickets.each_with_index do |ticket, i|
49
+ ticket_data = get_value(fields, ticket)
50
+
51
+ mode = (i.zero? ? "w+" : "a+")
52
+ File.open(filename.to_s, mode) do |txt|
53
+ txt.puts(ticket_data)
54
+ end
55
+ end
56
+ end
57
+
58
+ def get_value(fields, ticket)
59
+ data = ""
60
+ fields.each do |field|
61
+ value = available_value?(ticket, field)
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
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sunat_books/ple/base"
4
+
5
+ module SunatBooks
6
+ module Ple
7
+ class Buys < Base
8
+ def initialize(ruc, tickets, month, year, options = {})
9
+ # ruc => company's ruc in string format
10
+ # tickets => an array of objects that respond to a layout's methods
11
+ # month => a number that represent a month
12
+ # year => a number that represent a year
13
+ # options =>
14
+ # :yml => to define a custom layout file
15
+ # :layout => to define a custom name for a specific layout method
16
+
17
+ book_name = self.class.name.downcase.sub("sunatbooks::ple::", "")
18
+ dir = File.dirname(__FILE__)
19
+ yml_path = options[:yml] || "#{dir}/layouts/#{book_name}.yml"
20
+ fields = YAML.load_file(yml_path)
21
+ check_layout(options, fields)
22
+ content = !tickets.empty? ? 1 : 0
23
+ name = ple_book_name("8.1", ruc, month, year, nil, content)
24
+
25
+ filename = "#{path}#{name}.txt"
26
+ get_file(tickets, fields, filename)
27
+ end
28
+
29
+ def insert_layout_fields(options, fields)
30
+ options[:layout].each do |key, value|
31
+ i = fields.index(key.to_s)
32
+ fields.delete(key.to_s)
33
+ fields.insert(i, value)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sunat_books/ple/base"
4
+
5
+ module SunatBooks
6
+ module Ple
7
+ class Sales < Base
8
+ def initialize(ruc, tickets, month, year, options = {})
9
+ book_name = self.class.name.downcase.sub("sunatbooks::ple::", "")
10
+ dir = File.dirname(__FILE__)
11
+ yml_path = options[:yml] || "#{dir}/layouts/#{book_name}.yml"
12
+ fields = YAML.load_file(yml_path)
13
+ check_layout(options, fields)
14
+ content = !tickets.empty? ? 1 : 0
15
+
16
+ name = ple_book_name("14.2", ruc, month, year, nil, content)
17
+ @filename = "#{path}#{name}.txt"
18
+ get_file(tickets, fields, @filename)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -2,8 +2,8 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "sunat_books"
5
- s.version = "0.0.2"
6
- s.summary = "SUNAT books"
5
+ s.version = "0.0.3"
6
+ s.summary = "A ruby gem to get accounting books for SUNAT"
7
7
  s.description = s.summary
8
8
  s.authors = ["César Carruitero"]
9
9
  s.email = ["cesar@mozilla.pe"]
@@ -1,18 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../helper"
4
- require_relative "../../lib/csv_books/option_error"
4
+ require "sunat_books/csv/option_error"
5
5
 
6
6
  setup do
7
7
  @tickets = []
8
8
  5.times do
9
9
  @tickets << Ticket.new(field: SecureRandom.hex(10))
10
10
  end
11
- @base = CsvBooks::Base.new(@tickets, layout: ["field"])
11
+ @base = SunatBooks::Csv::Base.new(@tickets, layout: ["field"])
12
12
  end
13
13
 
14
14
  test "require a layout array" do
15
- assert_raise(CsvBooks::OptionError) { CsvBooks::Base.new(@tickets) }
15
+ assert_raise(SunatBooks::Csv::OptionError) do
16
+ SunatBooks::Csv::Base.new(@tickets)
17
+ end
16
18
  end
17
19
 
18
20
  test "should generate csv" do
@@ -20,13 +22,14 @@ test "should generate csv" do
20
22
  end
21
23
 
22
24
  test "should allow set custom filename" do
23
- custom_file = CsvBooks::Base.new(@tickets, layout: [], filename: "name.csv")
25
+ options = { layout: [], filename: "name.csv" }
26
+ custom_file = SunatBooks::Csv::Base.new(@tickets, options)
24
27
  assert custom_file.file.include?("name.csv")
25
28
  assert File.exist?(custom_file.file)
26
29
  end
27
30
 
28
31
  test "should handle undefined layout method" do
29
- undefined_method = CsvBooks::Base.new(@tickets, layout: %w[field bar])
32
+ undefined_method = SunatBooks::Csv::Base.new(@tickets, layout: %w[field bar])
30
33
  assert File.exist?(undefined_method.file)
31
34
  end
32
35
 
File without changes
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../helper"
4
+
5
+ setup do
6
+ @company = Company.new(ruc: Faker::Number.number(11), name: Faker::Name.name)
7
+ end
8
+
9
+ test "render pdf, have a parseable pdf" do
10
+ tickets = []
11
+ pdf = SunatBooks::Pdf::Buys.new(@company, tickets, 2, 3015)
12
+ page_counter = PDF::Inspector::Page.analyze(pdf.render)
13
+ assert pdf.page_count == 1
14
+ assert page_counter.pages.size == 1
15
+ end
16
+
17
+ test "@book_name instance variable is correct" do
18
+ book = SunatBooks::Pdf::Buys.new(@company, [], 2, 3015)
19
+ assert_equal book.instance_variable_get("@book_name"), "buys"
20
+ end
21
+
22
+ test "have correct text in header" do
23
+ tickets = []
24
+ pdf = SunatBooks::Pdf::Buys.new(@company, tickets, 2, 3015)
25
+ reader = PDF::Reader.new(StringIO.new(pdf.render))
26
+ assert reader.pages.first.text.include?("REGISTRO DE COMPRAS")
27
+ end