sunat_invoice 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.mkd +1 -25
- data/lib/sunat_invoice/client.rb +3 -6
- data/lib/sunat_invoice/clients/consult_client.rb +17 -0
- data/lib/sunat_invoice/clients/invoice_client.rb +11 -3
- data/lib/sunat_invoice/configuration.rb +1 -1
- data/lib/sunat_invoice/credit_note.rb +59 -0
- data/lib/sunat_invoice/credit_note_line.rb +15 -0
- data/lib/sunat_invoice/customer.rb +1 -0
- data/lib/sunat_invoice/daily_summary.rb +46 -0
- data/lib/sunat_invoice/debit_note.rb +33 -0
- data/lib/sunat_invoice/debit_note_line.rb +15 -0
- data/lib/sunat_invoice/invoice.rb +23 -144
- data/lib/sunat_invoice/item.rb +40 -26
- data/lib/sunat_invoice/line.rb +18 -0
- data/lib/sunat_invoice/provider.rb +20 -14
- data/lib/sunat_invoice/response_parser.rb +64 -0
- data/lib/sunat_invoice/signature.rb +29 -15
- data/lib/sunat_invoice/summary_line.rb +75 -0
- data/lib/sunat_invoice/tax.rb +6 -1
- data/lib/sunat_invoice/trade_calculations.rb +68 -0
- data/lib/sunat_invoice/trade_document.rb +85 -0
- data/lib/sunat_invoice/utils.rb +48 -9
- data/lib/sunat_invoice/voided.rb +22 -0
- data/lib/sunat_invoice/voided_line.rb +20 -0
- data/lib/sunat_invoice/xml_document.rb +52 -0
- data/lib/sunat_invoice.rb +14 -0
- data/sunat_invoice.gemspec +5 -5
- data/test/credit_note_test.rb +15 -0
- data/test/daily_summary_test.rb +35 -0
- data/test/debit_note_test.rb +15 -0
- data/test/factories.rb +70 -0
- data/test/fixtures/responses/invoice_success.xml +2 -0
- data/test/fixtures/responses/summary_success.xml +2 -0
- data/test/fixtures/responses/ticket_invalid.xml +2 -0
- data/test/helper.rb +1 -0
- data/test/invoice_client_test.rb +68 -16
- data/test/invoice_test.rb +19 -10
- data/test/item_test.rb +3 -2
- data/test/response_parser_test.rb +28 -0
- data/test/support/response_helper.rb +18 -0
- data/test/support/signature_helper.rb +15 -8
- metadata +34 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c15a897331d06af16937c9bf1020984592bcd0f3
|
4
|
+
data.tar.gz: 51cc6c5c299e0d2209a32ccc51be2158b7a4e780
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5866087a7d0c40c4c88ad32ee94812d7e3dbd75892968ca39df00aa501fcdb9167a0ba06b60c3c38d0095b51c631d6de51055e01dfee4f4db029c473bac4b91
|
7
|
+
data.tar.gz: 20781a7b8110190a887a7c9740fbfebb4a8fd55893953a07fc12c8da05f549d1fae2630b301bc98329db94dc39c2ca23f2ce017541409774013d034c4626062e
|
data/Gemfile
CHANGED
data/README.mkd
CHANGED
@@ -1,26 +1,2 @@
|
|
1
1
|
# Sunat Invoice
|
2
|
-
Ruby
|
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
|
data/lib/sunat_invoice/client.rb
CHANGED
@@ -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
|
29
|
-
|
30
|
-
|
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)
|
@@ -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,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
|
@@ -1,171 +1,50 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
|
-
|
2
|
+
|
3
3
|
require_relative 'provider'
|
4
4
|
require_relative 'customer'
|
5
5
|
require_relative 'signature'
|
6
|
-
require_relative '
|
7
|
-
require_relative 'catalogs'
|
6
|
+
require_relative 'trade_document'
|
8
7
|
|
9
8
|
module SunatInvoice
|
10
|
-
class Invoice <
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
@
|
21
|
+
@lines ||= []
|
28
22
|
@signature = SunatInvoice::Signature.new(provider: @provider)
|
29
23
|
end
|
30
24
|
|
31
|
-
def
|
32
|
-
|
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
|
127
|
-
|
128
|
-
|
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
|
-
|
133
|
-
|
36
|
+
invoice_xml = build.to_xml
|
37
|
+
@signature.sign(invoice_xml)
|
134
38
|
end
|
135
39
|
|
136
|
-
|
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
|
147
|
-
|
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
|
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
|
data/lib/sunat_invoice/item.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require_relative 'utils'
|
3
2
|
|
4
|
-
|
5
|
-
class Item < Model
|
6
|
-
include Utils
|
3
|
+
require_relative 'line'
|
7
4
|
|
8
|
-
|
9
|
-
|
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
|
49
|
-
xml['
|
50
|
-
|
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
|
74
|
-
|
75
|
-
|
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, :
|
10
|
-
|
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
|