sunat_invoice 0.0.1 → 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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/README.mkd +1 -25
  4. data/lib/sunat_invoice/client.rb +3 -6
  5. data/lib/sunat_invoice/clients/consult_client.rb +17 -0
  6. data/lib/sunat_invoice/clients/invoice_client.rb +11 -3
  7. data/lib/sunat_invoice/configuration.rb +1 -1
  8. data/lib/sunat_invoice/credit_note.rb +59 -0
  9. data/lib/sunat_invoice/credit_note_line.rb +15 -0
  10. data/lib/sunat_invoice/customer.rb +1 -0
  11. data/lib/sunat_invoice/daily_summary.rb +46 -0
  12. data/lib/sunat_invoice/debit_note.rb +33 -0
  13. data/lib/sunat_invoice/debit_note_line.rb +15 -0
  14. data/lib/sunat_invoice/invoice.rb +23 -144
  15. data/lib/sunat_invoice/item.rb +40 -26
  16. data/lib/sunat_invoice/line.rb +18 -0
  17. data/lib/sunat_invoice/provider.rb +20 -14
  18. data/lib/sunat_invoice/response_parser.rb +64 -0
  19. data/lib/sunat_invoice/signature.rb +29 -15
  20. data/lib/sunat_invoice/summary_line.rb +75 -0
  21. data/lib/sunat_invoice/tax.rb +6 -1
  22. data/lib/sunat_invoice/trade_calculations.rb +68 -0
  23. data/lib/sunat_invoice/trade_document.rb +85 -0
  24. data/lib/sunat_invoice/utils.rb +48 -9
  25. data/lib/sunat_invoice/voided.rb +22 -0
  26. data/lib/sunat_invoice/voided_line.rb +20 -0
  27. data/lib/sunat_invoice/xml_document.rb +52 -0
  28. data/lib/sunat_invoice.rb +14 -0
  29. data/sunat_invoice.gemspec +5 -5
  30. data/test/credit_note_test.rb +15 -0
  31. data/test/daily_summary_test.rb +35 -0
  32. data/test/debit_note_test.rb +15 -0
  33. data/test/factories.rb +70 -0
  34. data/test/fixtures/responses/invoice_success.xml +2 -0
  35. data/test/fixtures/responses/summary_success.xml +2 -0
  36. data/test/fixtures/responses/ticket_invalid.xml +2 -0
  37. data/test/helper.rb +1 -0
  38. data/test/invoice_client_test.rb +68 -16
  39. data/test/invoice_test.rb +19 -10
  40. data/test/item_test.rb +3 -2
  41. data/test/response_parser_test.rb +28 -0
  42. data/test/support/response_helper.rb +18 -0
  43. data/test/support/signature_helper.rb +15 -8
  44. metadata +34 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b49429704d8a0fd453f1210ee274c0b111dbb96e
4
- data.tar.gz: ecae8df2666c3e508abea79a594c375b12b03153
3
+ metadata.gz: c15a897331d06af16937c9bf1020984592bcd0f3
4
+ data.tar.gz: 51cc6c5c299e0d2209a32ccc51be2158b7a4e780
5
5
  SHA512:
6
- metadata.gz: 83d17d8b14f0bfb1bcbdea6e449346d7ac0b819859d434695f93ba306e8f979f0885683454fd655d1bfb54f4ee9f60cbe16e0266e429b1507df75d6745365d82
7
- data.tar.gz: c1992a23ae4817da9539e980bc3ee745335d70b802d1a18a32793eee7c6918140af4915ae84cd72c6e30a7b8edb2077808f656f596c0e8b4446cdf3eba362865
6
+ metadata.gz: a5866087a7d0c40c4c88ad32ee94812d7e3dbd75892968ca39df00aa501fcdb9167a0ba06b60c3c38d0095b51c631d6de51055e01dfee4f4db029c473bac4b91
7
+ data.tar.gz: 20781a7b8110190a887a7c9740fbfebb4a8fd55893953a07fc12c8da05f549d1fae2630b301bc98329db94dc39c2ca23f2ce017541409774013d034c4626062e
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  source 'https://rubygems.org'
3
4
 
4
5
  gemspec
data/README.mkd CHANGED
@@ -1,26 +1,2 @@
1
1
  # Sunat Invoice
2
- Ruby wrapper to use SUNAT Electronic Invoice API
3
-
4
- homologacion
5
- https://www.sunat.gob.pe/ol-ti-itcpgem-sqa/billService?wsdl
6
-
7
- valid_service
8
-
9
- http://www.sunat.gob.pe/ol-ti-itconsvalicpe/ConsValiCpe.htm
10
-
11
- {:validaCDPcriterios=>{:rucEmisor=>"string", :tipoCDP=>"string", :serieCDP=>"string", :numeroCDP=>"string", :tipoDocIdReceptor=>"string", :numeroDocIdReceptor=>"string", :fechaEmision=>"string", :importeTotal=>"double", :nroAutorizacion=>"string"}}
12
-
13
- http://www.sunat.gob.pe/ol-ti-itconsverixml/ConsVeriXml.htm
14
-
15
- {:verificaCPEarchivo=>{:nombre=>"string", :archivo=>"string"}}
16
-
17
- errors
18
- https://www.facturacionperu.ws/?p=138
19
-
20
-
21
- To write:
22
- https://www.xml.com/pub/a/2001/08/08/xmldsig.html
23
- https://www.di-mgt.com.au/xmldsig.html
24
-
25
- https://github.com/ebeigarts/signer
26
- https://github.com/benoist/xmldsig
2
+ Ruby gem to use [SUNAT Electronic Billing](http://cpe.sunat.gob.pe/factura-desde-los-sistemas-del-contribuyente) from your app
@@ -5,15 +5,12 @@ require 'savon'
5
5
 
6
6
  module SunatInvoice
7
7
  class Client
8
- def initialize(env = 'dev')
8
+ def initialize(env = 'dev', log = false)
9
9
  @env = env
10
+ @log = log
10
11
  @soap_client = savon_client
11
12
  end
12
13
 
13
- def log
14
- (@env != 'prod')
15
- end
16
-
17
14
  private
18
15
 
19
16
  def config
@@ -30,7 +27,7 @@ module SunatInvoice
30
27
  Savon.client(wsdl: wsdl,
31
28
  wsse_auth: authentication,
32
29
  namespace: 'http://service.sunat.gob.pe',
33
- log: log)
30
+ log: @log)
34
31
  end
35
32
  end
36
33
  end
@@ -7,5 +7,22 @@ module SunatInvoice
7
7
  def wsdl
8
8
  'https://www.sunat.gob.pe/ol-it-wsconscpegem/billConsultService?wsdl'
9
9
  end
10
+
11
+ def get_status(ticket)
12
+ @soap_client.call(:get_status, message: { ticket: ticket })
13
+ end
14
+
15
+ def get_status_cdr(options = {})
16
+ # Available document_type to use:
17
+ # 01: Factura.
18
+ # 07: Nota de crédito.
19
+ # 08: Nota de débito
20
+ @soap_client.call(:get_status, message: {
21
+ rucComprobante: options[:ruc],
22
+ tipoComprobante: options[:document_type],
23
+ serieComprobante: options[:document_serial],
24
+ numeroComprobante: options[:document_number]
25
+ })
26
+ end
10
27
  end
11
28
  end
@@ -25,12 +25,20 @@ module SunatInvoice
25
25
  encode(zip_file.sysread)
26
26
  end
27
27
 
28
- def send_invoice(invoice, name)
29
- zip = prepare_zip(invoice, "#{name}.xml")
30
- @soap_client.call(:send_bill,
28
+ def dispatch(document)
29
+ # * document - Invoice or DailySummary instance
30
+ xml_build = document.xml
31
+ name = document.document_name
32
+ operation = document.operation
33
+ zip = prepare_zip(xml_build, "#{name}.xml")
34
+ @soap_client.call(operation,
31
35
  message: { fileName: "#{name}.zip", contentFile: zip })
32
36
  end
33
37
 
38
+ def get_status(ticket)
39
+ @soap_client.call(:get_status, message: { ticket: ticket })
40
+ end
41
+
34
42
  private
35
43
 
36
44
  def encode(zip_str)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SunatInvoice
4
4
  class Configuration
5
- attr_accessor :account_ruc, :account_user, :account_password, :provider
5
+ attr_accessor :account_ruc, :account_user, :account_password
6
6
  end
7
7
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'trade_document'
4
+
5
+ module SunatInvoice
6
+ class CreditNote < TradeDocument
7
+ # * date - issued date
8
+ # * ref_document_number - serial and number of document affected
9
+ # * ref_document_type - type of document affected
10
+ # * response_code - reason for which credit note is issued (CATALOG_09)
11
+ # * description - description of reason
12
+ # * document_type - should be '07' according CATALOG_01
13
+ # * document_number - serial and correlative number of document
14
+ # * provider - a SunatInvoice::Provider instance
15
+ # * customer - a SunatInvoice::Customer instance
16
+ # * signature - a SunatInvoice::Signature instance
17
+ # * lines - array of SunatInvoice::CreditNoteLine instances
18
+
19
+ attr_accessor :ref_document_number, :ref_document_type, :response_code,
20
+ :description
21
+
22
+ def xml
23
+ build = build_xml do |xml|
24
+ build_document_data(xml)
25
+ build_discrepancy_response(xml)
26
+ build_billing_reference(xml)
27
+ build_common_content(xml)
28
+ end
29
+ @signature.sign(build.to_xml)
30
+ end
31
+
32
+ private
33
+
34
+ def root_name
35
+ 'CreditNote'
36
+ end
37
+
38
+ def namespaces
39
+ CREDIT_NOTE_NAMESPACES.merge(TRADE_NAMESPACES)
40
+ end
41
+
42
+ def build_discrepancy_response(xml)
43
+ xml['cac'].DiscrepancyResponse do
44
+ xml['cbc'].ReferenceID ref_document_number
45
+ xml['cbc'].ResponseCode response_code # CATALOG_09
46
+ xml['cbc'].Description description
47
+ end
48
+ end
49
+
50
+ def build_billing_reference(xml)
51
+ xml['cac'].BillingReference do
52
+ xml['cac'].InvoiceDocumentReference do
53
+ xml['cbc'].ID ref_document_number
54
+ xml['cbc'].DocumentTypeCode ref_document_type
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'item'
4
+
5
+ module SunatInvoice
6
+ class CreditNoteLine < Item
7
+ def line_tag_name
8
+ 'CreditNoteLine'
9
+ end
10
+
11
+ def quantity_tag_name
12
+ 'CreditedQuantity'
13
+ end
14
+ end
15
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'tributer'
3
4
 
4
5
  module SunatInvoice
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SunatInvoice
4
+ class DailySummary < XmlDocument
5
+ attr_accessor :reference_date
6
+
7
+ def namespaces
8
+ DAILY_SUMMARY_NAMESPACES.merge(SUMMARY_NAMESPACES)
9
+ end
10
+
11
+ def xml
12
+ build = build_xml do |xml|
13
+ build_number(xml)
14
+ build_summary_info(xml)
15
+ @signature.signer_data(xml)
16
+ @provider.info(xml, false)
17
+ build_lines_xml(xml)
18
+ end
19
+ @signature.sign(build.to_xml)
20
+ end
21
+
22
+ def operation
23
+ :send_summary
24
+ end
25
+
26
+ def document_name
27
+ "#{@provider.ruc}-#{document_number}"
28
+ end
29
+
30
+ private
31
+
32
+ def root_name
33
+ 'SummaryDocuments'
34
+ end
35
+
36
+ def document_number
37
+ formatted = date.strftime('%Y%m%d') # YYYYMMDD
38
+ "RC-#{formatted}-1"
39
+ end
40
+
41
+ def build_summary_info(xml)
42
+ xml['cbc'].ReferenceDate formatted_date(reference_date)
43
+ xml['cbc'].IssueDate formatted_date(date)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'credit_note'
4
+
5
+ module SunatInvoice
6
+ class DebitNote < CreditNote
7
+ # * date - issued date
8
+ # * ref_document_number - serial and number of document affected
9
+ # * ref_document_type - type of document affected
10
+ # * response_code - reason for which debit note is issued (CATALOG_10)
11
+ # * description - description of reason
12
+ # * document_type - should be '08' according CATALOG_01
13
+ # * document_number - serial and correlative number of document
14
+ # * provider - a SunatInvoice::Provider instance
15
+ # * customer - a SunatInvoice::Customer instance
16
+ # * signature - a SunatInvoice::Signature instance
17
+ # * lines - array of SunatInvoice::DebitNoteLine instances
18
+
19
+ private
20
+
21
+ def root_name
22
+ 'DebitNote'
23
+ end
24
+
25
+ def namespaces
26
+ DEBIT_NOTE_NAMESPACES.merge(TRADE_NAMESPACES)
27
+ end
28
+
29
+ def total_tag
30
+ 'RequestedMonetaryTotal'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'item'
4
+
5
+ module SunatInvoice
6
+ class DebitNoteLine < Item
7
+ def line_tag_name
8
+ 'DebitNoteLine'
9
+ end
10
+
11
+ def quantity_tag_name
12
+ 'DebitedQuantity'
13
+ end
14
+ end
15
+ end
@@ -1,171 +1,50 @@
1
1
  # frozen_string_literal: false
2
- require_relative 'utils'
2
+
3
3
  require_relative 'provider'
4
4
  require_relative 'customer'
5
5
  require_relative 'signature'
6
- require_relative 'tax'
7
- require_relative 'catalogs'
6
+ require_relative 'trade_document'
8
7
 
9
8
  module SunatInvoice
10
- class Invoice < Model
11
- include Utils
12
-
13
- attr_accessor :document_type, :document_number, :items
14
-
15
- UBL_VERSION = '2.0'
16
- CUSTOMIZATION = '1.0'
17
-
9
+ class Invoice < TradeDocument
18
10
  def initialize(*args)
19
11
  super(*args)
20
12
  opts = args[0] || {}
21
- @provider = opts[:provider] || SunatInvoice::Provider.new
22
- @customer = opts[:customer] || SunatInvoice::Customer.new
23
- @date = opts[:date] || DateTime.now.strftime('%Y-%m-%d')
13
+ init_defaults(opts)
14
+ end
15
+
16
+ def init_defaults(opts)
17
+ parties_default(opts)
24
18
  @document_type = opts[:document_type] || '01'
25
19
  @document_number = opts[:document_number] || 'F001-1'
26
20
  @currency = opts[:currency] || 'PEN'
27
- @items ||= []
21
+ @lines ||= []
28
22
  @signature = SunatInvoice::Signature.new(provider: @provider)
29
23
  end
30
24
 
31
- def xml
32
- prepare_totals
33
-
34
- build = Nokogiri::XML::Builder.new do |xml|
35
- xml.Invoice(UBL_NAMESPACES) do
36
- xml['ext'].UBLExtensions do
37
- build_sale_totals(xml)
38
- @signature.signature_ext(xml)
39
- end
40
-
41
- xml['cbc'].UBLVersionID UBL_VERSION
42
- xml['cbc'].CustomizationID CUSTOMIZATION
43
- xml['cbc'].ID @document_number
44
- xml['cbc'].IssueDate @date
45
- xml['cbc'].InvoiceTypeCode @document_type
46
- xml['cbc'].DocumentCurrencyCode @currency
47
-
48
- @signature.signer_data(xml)
49
- @provider.info(xml)
50
- @customer.info(xml)
51
- build_tax_totals(xml)
52
- build_total(xml)
53
- build_items(xml)
54
- end
55
- end
56
- invoice_xml = build.to_xml
57
- @signature.sign(invoice_xml)
58
- end
59
-
60
- def prepare_totals
61
- calculate_tax_totals
62
- calculate_sale_totals
63
- calculate_total
64
- end
65
-
66
- def calculate_total
67
- # calculate invoice total
68
- @total = 0
69
- @total += @tax_totals.values.sum
70
- @total += @sale_totals.values.sum
71
- end
72
-
73
- def calculate_sale_totals
74
- @sale_totals = {}
75
- # get bi totals according kind of sale (gravado, inafecto, exonerado ..)
76
- items.each do |item|
77
- # TODO: I think in most cases only be one tax for item, but should
78
- # handle more cases
79
- total_code = get_total_code(item.taxes.first)
80
- if total_code
81
- @sale_totals[total_code] = 0 unless @sale_totals[total_code]
82
- @sale_totals[total_code] += item.bi_value
83
- end
84
- end
85
- end
86
-
87
- def calculate_tax_totals
88
- # concat item's sale_taxes
89
- @tax_totals = {}
90
- taxes = items.map(&:sale_taxes).flatten
91
- taxes.each do |tax|
92
- @tax_totals[tax.keys.first] ||= 0
93
- @tax_totals[tax.keys.first] += tax.values.sum
94
- end
95
- end
96
-
97
- def build_items(xml)
98
- items.each_with_index do |item, index|
99
- item.xml(xml, index, @currency)
100
- end
101
- end
102
-
103
- def document_name
104
- "#{@provider.ruc}-#{document_type}-#{document_number}"
105
- end
106
-
107
- def build_tax_totals(xml)
108
- @tax_totals.each do |key, value|
109
- SunatInvoice::Tax.new(tax_type: key, amount: value).xml(xml, @currency)
110
- end
111
- end
112
-
113
- def build_sale_totals(xml)
114
- ubl_ext(xml) do
115
- xml['sac'].AdditionalInformation do
116
- @sale_totals.each do |code, amount|
117
- xml['sac'].AdditionalMonetaryTotal do
118
- xml['cbc'].ID code
119
- amount_xml(xml['cbc'], 'PayableAmount', amount, @currency)
120
- end
121
- end
122
- end
123
- end
25
+ def parties_default(opts)
26
+ @provider = opts[:provider] || SunatInvoice::Provider.new
27
+ @customer = opts[:customer] || SunatInvoice::Customer.new
124
28
  end
125
29
 
126
- def build_total(xml)
127
- xml['cac'].LegalMonetaryTotal do
128
- amount_xml(xml['cbc'], 'PayableAmount', @total, @currency)
30
+ def xml
31
+ build = build_xml do |xml|
32
+ build_document_data(xml)
33
+ build_common_content(xml)
129
34
  end
130
- end
131
35
 
132
- def add_item(item)
133
- items << item if item.is_a?(SunatInvoice::Item)
36
+ invoice_xml = build.to_xml
37
+ @signature.sign(invoice_xml)
134
38
  end
135
39
 
136
- def get_total_code(tax)
137
- return unless tax
138
- case tax.tax_type
139
- when :igv
140
- get_total_igv_code(tax.tax_exemption_reason)
141
- # when :isc
142
- # tax.tier_range
143
- end
144
- end
40
+ private
145
41
 
146
- def get_total_igv_code(exemption_reason)
147
- if Catalogs::CATALOG_07.first == exemption_reason
148
- Catalogs::CATALOG_14.first
149
- elsif Catalogs::CATALOG_07[1..6].include?(exemption_reason)
150
- Catalogs::CATALOG_14[3]
151
- elsif Catalogs::CATALOG_07[7] == exemption_reason
152
- Catalogs::CATALOG_14[2]
153
- elsif Catalogs::CATALOG_07[8..14].include?(exemption_reason)
154
- Catalogs::CATALOG_14[1]
155
- end
42
+ def root_name
43
+ 'Invoice'
156
44
  end
157
45
 
158
- def attributes
159
- {
160
- attributes!: {
161
- 'cbc:InvoicedQuantity' => { '@unitCode' => :unit },
162
- 'cbc:PriceAmount' => { '@currencyID' => :currency }, # PEN
163
- 'cbc:TaxAmount' => { '@currencyID' => :currency }, # PEN
164
- 'cbc:PayableAmount' => { '@currencyID' => :currency }, # PEN
165
- 'cbc:LineExtensionAmount' => { '@currencyID' => :currency }, # PEN
166
- 'cbc:ChargeTotalAmount' => { '@currencyID' => :currency }, # PEN
167
- }
168
- }
46
+ def namespaces
47
+ INVOICE_NAMESPACES.merge(TRADE_NAMESPACES)
169
48
  end
170
49
  end
171
50
  end
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
- require_relative 'utils'
3
2
 
4
- module SunatInvoice
5
- class Item < Model
6
- include Utils
3
+ require_relative 'line'
7
4
 
8
- attr_accessor :quantity, :description, :price, :price_code, :unit_code,
9
- :taxes
5
+ module SunatInvoice
6
+ class Item < Line
7
+ attr_accessor :quantity, :description, :price, :price_code, :unit_code
10
8
 
11
9
  def initialize(*args)
12
10
  # * quantity - quantity of item
@@ -21,6 +19,25 @@ module SunatInvoice
21
19
  @taxes ||= []
22
20
  end
23
21
 
22
+ def line_tag_name
23
+ 'InvoiceLine'
24
+ end
25
+
26
+ def quantity_tag_name
27
+ 'InvoicedQuantity'
28
+ end
29
+
30
+ def xml(xml, index, currency)
31
+ xml['cac'].send(line_tag_name) do
32
+ build_basic_line_xml(xml, index)
33
+ amount_xml(xml['cbc'], 'LineExtensionAmount', bi_value, currency)
34
+ build_pricing_reference(xml, currency)
35
+ build_taxes_xml(xml, currency)
36
+ build_item(xml)
37
+ build_price(xml, currency)
38
+ end
39
+ end
40
+
24
41
  def bi_value
25
42
  # bi of sale = price without taxes * quantity
26
43
  (@price.to_f * @quantity.to_f).round(2)
@@ -41,27 +58,15 @@ module SunatInvoice
41
58
  (@price.to_f + sum_taxes).round(2)
42
59
  end
43
60
 
61
+ private
62
+
44
63
  def sum_taxes
45
64
  taxes.map(&:amount).sum
46
65
  end
47
66
 
48
- def xml(xml, index, currency)
49
- xml['cac'].InvoiceLine do
50
- xml['cbc'].ID(index + 1)
51
- xml['cbc'].InvoicedQuantity(@quantity, unitCode: unit_code)
52
- amount_xml(xml['cbc'], 'LineExtensionAmount', bi_value, currency)
53
- xml['cac'].PricingReference do
54
- xml['cac'].AlternativeConditionPrice do
55
- amount_xml(xml['cbc'], 'PriceAmount', sale_price, currency)
56
- xml['cbc'].PriceTypeCode price_code
57
- end
58
- end
59
- taxes_xml(xml, currency)
60
- build_item(xml)
61
- xml['cac'].Price do
62
- amount_xml(xml['cbc'], 'PriceAmount', price, currency)
63
- end
64
- end
67
+ def build_basic_line_xml(xml, index)
68
+ xml['cbc'].ID(index + 1)
69
+ xml['cbc'].send(quantity_tag_name, quantity, unitCode: unit_code)
65
70
  end
66
71
 
67
72
  def build_item(xml)
@@ -70,9 +75,18 @@ module SunatInvoice
70
75
  end
71
76
  end
72
77
 
73
- def taxes_xml(xml, currency)
74
- taxes&.each do |tax|
75
- tax.xml(xml, currency)
78
+ def build_pricing_reference(xml, currency)
79
+ xml['cac'].PricingReference do
80
+ xml['cac'].AlternativeConditionPrice do
81
+ amount_xml(xml['cbc'], 'PriceAmount', sale_price, currency)
82
+ xml['cbc'].PriceTypeCode price_code
83
+ end
84
+ end
85
+ end
86
+
87
+ def build_price(xml, currency)
88
+ xml['cac'].Price do
89
+ amount_xml(xml['cbc'], 'PriceAmount', price, currency)
76
90
  end
77
91
  end
78
92
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'model'
4
+ require_relative 'utils'
5
+
6
+ module SunatInvoice
7
+ class Line < Model
8
+ include Utils
9
+
10
+ attr_accessor :taxes
11
+
12
+ def build_taxes_xml(xml, currency)
13
+ taxes&.each do |tax|
14
+ tax.xml(xml, currency)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'tributer'
3
4
  require_relative 'utils'
4
5
 
@@ -6,8 +7,25 @@ module SunatInvoice
6
7
  class Provider < Tributer
7
8
  include Utils
8
9
 
9
- attr_accessor :signature_id, :signature_location_id, :uri, :pk_file,
10
- :cert_file
10
+ attr_accessor :signature_id, :signature_location_id, :pk_file, :cert_file
11
+
12
+ def info(xml, with_address = true)
13
+ xml['cac'].AccountingSupplierParty do
14
+ xml['cbc'].CustomerAssignedAccountID ruc
15
+ xml['cbc'].AdditionalAccountID document_type
16
+ build_party_xml(xml, with_address)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def build_party_xml(xml, with_address)
23
+ xml['cac'].Party do
24
+ build_name(xml)
25
+ xml['cac'].PostalAddress { address(xml) } if with_address
26
+ build_registration_name(xml)
27
+ end
28
+ end
11
29
 
12
30
  def address(xml)
13
31
  xml['cbc'].ID @ubigeo
@@ -36,17 +54,5 @@ module SunatInvoice
36
54
  xml['cbc'].RegistrationName name
37
55
  end
38
56
  end
39
-
40
- def info(xml)
41
- xml['cac'].AccountingSupplierParty do
42
- xml['cbc'].CustomerAssignedAccountID ruc
43
- xml['cbc'].AdditionalAccountID document_type
44
- xml['cac'].Party do
45
- build_name(xml)
46
- xml['cac'].PostalAddress { address(xml) }
47
- build_registration_name(xml)
48
- end
49
- end
50
- end
51
57
  end
52
58
  end