afip.rb 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +49 -0
- data/LICENSE.txt +21 -0
- data/README.md +50 -0
- data/Rakefile +8 -0
- data/afip.gemspec +36 -0
- data/lib/afip/electronic_billing.rb +256 -0
- data/lib/afip/register_inscription_proof.rb +67 -0
- data/lib/afip/register_scope_ten.rb +49 -0
- data/lib/afip/register_scope_thirteen.rb +67 -0
- data/lib/afip/version.rb +5 -0
- data/lib/afip/web_service.rb +71 -0
- data/lib/afip.rb +124 -0
- data/sig/afip.rbs +4 -0
- metadata +58 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1cc5b723a5764b5bb0e78ed11bb03b06157ef1e334f538f4284e8fea712150fa
|
4
|
+
data.tar.gz: d993b725b9d7664c45c59c38c220bcb1a9bc0f5c159b12dca6970c79980c2ebd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d526e25cadd6f63f41596ad25453e9323dc4da5cfdf83233ae3a76c7262b8ffb0c86e57aceaf7355fcded889ebe9e8fdd80c5852245508609d1dc0feb2e9c75
|
7
|
+
data.tar.gz: 1ce71c5f5a02506ffb7dcb2661e08fd6a55a8b8820a69059c581ce91a4785b6c171ca159bb2879f7a0c485c1ac4ee45aff3fd811ae8dbcd6ec387e248d4c7b23
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.3
|
3
|
+
|
4
|
+
Style/StringLiterals:
|
5
|
+
Enabled: true
|
6
|
+
EnforcedStyle: double_quotes
|
7
|
+
|
8
|
+
Style/StringLiteralsInInterpolation:
|
9
|
+
Enabled: true
|
10
|
+
EnforcedStyle: double_quotes
|
11
|
+
|
12
|
+
Layout/LineLength:
|
13
|
+
Max: 130
|
14
|
+
|
15
|
+
Style/RescueStandardError:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Naming/MethodName:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Naming/VariableName:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Metrics/AbcSize:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Metrics/CyclomaticComplexity:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Metrics/MethodLength:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Style/OptionalBooleanParameter:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Style/Documentation:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Metrics/PerceivedComplexity:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
Naming/VariableNumber:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Style/NumericLiterals:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Metrics/ClassLength:
|
49
|
+
Enabled: false
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Ivan Muñoz
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
<!-- PROJECT SHIELDS -->
|
2
|
+
[![Contributors][contributors-shield]](https://github.com/afipsdk/afip.rb/graphs/contributors)
|
3
|
+
[![Closed issues][issues-shield]](https://github.com/afipsdk/afip.rb/issues)
|
4
|
+
|
5
|
+
|
6
|
+
<!-- PROJECT LOGO -->
|
7
|
+
<br />
|
8
|
+
<p align="center">
|
9
|
+
<a href="https://github.com/afipsdk/afip.rb">
|
10
|
+
<img src="https://github.com/afipsdk/afipsdk.github.io/blob/master/images/logo-colored.png" alt="Logo" width="130" height="130">
|
11
|
+
</a>
|
12
|
+
|
13
|
+
<h3 align="center">Afip.rb</h3>
|
14
|
+
|
15
|
+
<p align="center">
|
16
|
+
Librería para conectarse a los Web Services de AFIP en Ruby
|
17
|
+
<br />
|
18
|
+
<a href="https://docs.afipsdk.com"><strong>Explorar documentación »</strong></a>
|
19
|
+
<br />
|
20
|
+
<br />
|
21
|
+
<a href="https://github.com/afipsdk/afip.rb/issues">Reportar un bug</a>
|
22
|
+
</p>
|
23
|
+
</p>
|
24
|
+
|
25
|
+
|
26
|
+
<!-- DOCS -->
|
27
|
+
## Documentación
|
28
|
+
[Explorar documentación](https://docs.afipsdk.com)
|
29
|
+
|
30
|
+
<!-- ABOUT THE PROJECT -->
|
31
|
+
## Acerca del proyecto
|
32
|
+
Con más de 60.000 descargas en sus versiones de PHP, Node y Ruby desde el 2017 Afip SDK es la librería elegida por los desarrolladores para integrar sus plataformas con AFIP.
|
33
|
+
|
34
|
+
Esta librería fue creada con la intención de ayudar a los programadores a usar los Web Services de AFIP sin romperse la cabeza ni perder tiempo tratando de entender la complicada documentación que AFIP provee.
|
35
|
+
|
36
|
+
<!-- CONTACT -->
|
37
|
+
### Contacto
|
38
|
+
Afip SDK - afipsdk@gmail.com
|
39
|
+
|
40
|
+
Link del proyecto: [https://github.com/afipsdk/afip.rb](https://github.com/afipsdk/afip.rb)
|
41
|
+
|
42
|
+
|
43
|
+
_Este software y sus desarrolladores no tienen ninguna relación con la AFIP._
|
44
|
+
|
45
|
+
<!-- MARKDOWN LINKS & IMAGES -->
|
46
|
+
[packagist-shield]: https://img.shields.io/packagist/dt/afipsdk/afip.rb.svg??logo=php&?logoColor=white
|
47
|
+
[contributors-shield]: https://img.shields.io/github/contributors/afipsdk/afip.rb.svg?color=orange
|
48
|
+
[issues-shield]: https://img.shields.io/github/issues-closed-raw/afipsdk/afip.rb.svg?color=blueviolet
|
49
|
+
[license-shield]: https://img.shields.io/github/license/afipsdk/afip.rb.svg?color=blue
|
50
|
+
|
data/Rakefile
ADDED
data/afip.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/afip/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "afip.rb"
|
7
|
+
spec.version = Afip::VERSION
|
8
|
+
spec.authors = ["Afip SDK"]
|
9
|
+
spec.email = ["afipsdk@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Library to connect with AFIP"
|
12
|
+
spec.description = "AfipSDK is the easyest way to connect with AFIP"
|
13
|
+
spec.homepage = "https://afipsdk.com"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.3.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/AfipSDK/afip.rb"
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(__dir__) do
|
23
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
(File.expand_path(f) == __FILE__) ||
|
25
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
# Uncomment to register a new dependency of your gem
|
33
|
+
|
34
|
+
# For more information and examples about making a new gem, check out our
|
35
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
36
|
+
end
|
@@ -0,0 +1,256 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Afip
|
4
|
+
module WebServices
|
5
|
+
class ElectronicBilling < Afip::WebService
|
6
|
+
@soapv12 = true
|
7
|
+
@WSDL = "https://servicios1.afip.gov.ar/wsfev1/service.asmx?WSDL"
|
8
|
+
@URL = "https://servicios1.afip.gov.ar/wsfev1/service.asmx"
|
9
|
+
@WSDL_TEST = "https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL"
|
10
|
+
@URL_TEST = "https://wswhomo.afip.gov.ar/wsfev1/service.asmx"
|
11
|
+
|
12
|
+
def initialize(afip)
|
13
|
+
super(afip, { "service": "wsfe" })
|
14
|
+
end
|
15
|
+
|
16
|
+
# Create PDF
|
17
|
+
def createPDF(data)
|
18
|
+
url = URI("https://app.afipsdk.com/api/v1/pdfs")
|
19
|
+
|
20
|
+
https = Net::HTTP.new(url.host, url.port)
|
21
|
+
https.use_ssl = true
|
22
|
+
|
23
|
+
request = Net::HTTP::Post.new(url)
|
24
|
+
request["Content-Type"] = "application/json"
|
25
|
+
request["sdk-version-number"] = Afip::VERSION
|
26
|
+
request["sdk-library"] = "ruby"
|
27
|
+
request["sdk-environment"] = afip.production == true ? "prod" : "dev"
|
28
|
+
request["Authorization"] = "Bearer #{afip.access_token}" if afip.access_token
|
29
|
+
|
30
|
+
request.body = JSON.dump(data)
|
31
|
+
response = https.request(request)
|
32
|
+
|
33
|
+
unless response.is_a? Net::HTTPSuccess
|
34
|
+
begin
|
35
|
+
raise JSON.parse(response.read_body)
|
36
|
+
rescue
|
37
|
+
raise response.read_body
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
response_data = JSON.parse(response.read_body)
|
42
|
+
|
43
|
+
{ "file" => response_data["file"], "file_name" => response_data["file_name"] }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Gets last voucher number
|
47
|
+
def getLastVoucher(sales_point, type)
|
48
|
+
req = {
|
49
|
+
"PtoVta": sales_point,
|
50
|
+
"CbteTipo": type
|
51
|
+
}
|
52
|
+
|
53
|
+
executeRequest("FECompUltimoAutorizado", req)["CbteNro"]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Create a voucher from AFIP
|
57
|
+
def createVoucher(data, return_response = false)
|
58
|
+
# Reassign data to avoid modify te original object
|
59
|
+
data = JSON.parse(data.to_json)
|
60
|
+
|
61
|
+
req = {
|
62
|
+
"FeCAEReq": {
|
63
|
+
"FeCabReq": {
|
64
|
+
"CantReg": data["CbteHasta"] - data["CbteDesde"] + 1,
|
65
|
+
"PtoVta": data["PtoVta"],
|
66
|
+
"CbteTipo": data["CbteTipo"]
|
67
|
+
},
|
68
|
+
"FeDetReq": {
|
69
|
+
"FECAEDetRequest": data
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
data.delete("CantReg")
|
75
|
+
data.delete("PtoVta")
|
76
|
+
data.delete("CbteTipo")
|
77
|
+
|
78
|
+
data["Tributos"] = { "Tributo": data["Tributos"] } if data["Tributos"]
|
79
|
+
data["Iva"] = { "AlicIva": data["Iva"] } if data["Iva"]
|
80
|
+
data["CbtesAsoc"] = { "CbteAsoc": data["CbtesAsoc"] } if data["CbtesAsoc"]
|
81
|
+
data["Compradores"] = { "Comprador": data["Compradores"] } if data["Compradores"]
|
82
|
+
data["Opcionales"] = { "Opcional": data["Opcionales"] } if data["Opcionales"]
|
83
|
+
|
84
|
+
results = executeRequest("FECAESolicitar", req)
|
85
|
+
|
86
|
+
if return_response == true
|
87
|
+
results
|
88
|
+
else
|
89
|
+
if results["FeDetResp"]["FECAEDetResponse"].is_a?(Array)
|
90
|
+
results["FeDetResp"]["FECAEDetResponse"] = results["FeDetResp"]["FECAEDetResponse"][0]
|
91
|
+
end
|
92
|
+
|
93
|
+
{
|
94
|
+
"CAE" => results["FeDetResp"]["FECAEDetResponse"]["CAE"],
|
95
|
+
"CAEFchVto" => formatDate(results["FeDetResp"]["FECAEDetResponse"]["CAEFchVto"])
|
96
|
+
}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Create next voucher from AFIP
|
101
|
+
def createNextVoucher(data)
|
102
|
+
# Stringify keys
|
103
|
+
data = JSON.parse(data.to_json)
|
104
|
+
|
105
|
+
lastVoucher = getLastVoucher(data["PtoVta"], data["CbteTipo"])
|
106
|
+
|
107
|
+
voucherNumber = lastVoucher + 1
|
108
|
+
|
109
|
+
data["CbteDesde"] = voucherNumber
|
110
|
+
data["CbteHasta"] = voucherNumber
|
111
|
+
|
112
|
+
res = createVoucher(data)
|
113
|
+
|
114
|
+
res["voucherNumber"] = voucherNumber
|
115
|
+
|
116
|
+
res
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get complete voucher information
|
120
|
+
def getVoucherInfo(number, sales_point, type)
|
121
|
+
req = {
|
122
|
+
"FeCompConsReq": {
|
123
|
+
"CbteNro": number,
|
124
|
+
"PtoVta": sales_point,
|
125
|
+
"CbteTipo": type
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
executeRequest("FECompConsultar", req)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Create CAEA
|
133
|
+
def createCAEA(period, fortnight)
|
134
|
+
req = {
|
135
|
+
"Periodo": period,
|
136
|
+
"Orden": fortnight
|
137
|
+
}
|
138
|
+
|
139
|
+
executeRequest("FECAEASolicitar", req)["ResultGet"]
|
140
|
+
end
|
141
|
+
|
142
|
+
# Get CAEA
|
143
|
+
def getCAEA(period, fortnight)
|
144
|
+
req = {
|
145
|
+
"Periodo": period,
|
146
|
+
"Orden": fortnight
|
147
|
+
}
|
148
|
+
|
149
|
+
executeRequest("FECAEAConsultar", req)["ResultGet"]
|
150
|
+
end
|
151
|
+
|
152
|
+
# Asks to AFIP Servers for available sales points
|
153
|
+
def getSalesPoints
|
154
|
+
executeRequest("FEParamGetPtosVenta")["ResultGet"]["PtoVenta"]
|
155
|
+
end
|
156
|
+
|
157
|
+
# Asks to AFIP Servers for available voucher types
|
158
|
+
def getVoucherTypes
|
159
|
+
executeRequest("FEParamGetTiposCbte")["ResultGet"]["CbteTipo"]
|
160
|
+
end
|
161
|
+
|
162
|
+
# Asks to AFIP Servers for voucher concepts availables
|
163
|
+
def getConceptTypes
|
164
|
+
executeRequest("FEParamGetTiposConcepto")["ResultGet"]["ConceptoTipo"]
|
165
|
+
end
|
166
|
+
|
167
|
+
# Asks to AFIP Servers for document types availables
|
168
|
+
def getDocumentTypes
|
169
|
+
executeRequest("FEParamGetTiposDoc")["ResultGet"]["DocTipo"]
|
170
|
+
end
|
171
|
+
|
172
|
+
# Asks to AFIP Servers for available aliquotes
|
173
|
+
def getAliquotTypes
|
174
|
+
executeRequest("FEParamGetTiposIva")["ResultGet"]["IvaTipo"]
|
175
|
+
end
|
176
|
+
|
177
|
+
# Asks to AFIP Servers for available currencies
|
178
|
+
def getCurrenciesTypes
|
179
|
+
executeRequest("FEParamGetTiposMonedas")["ResultGet"]["Moneda"]
|
180
|
+
end
|
181
|
+
|
182
|
+
# Asks to AFIP Servers for available voucher optional data
|
183
|
+
def getOptionsTypes
|
184
|
+
executeRequest("FEParamGetTiposOpcional")["ResultGet"]["OpcionalTipo"]
|
185
|
+
end
|
186
|
+
|
187
|
+
# Asks to AFIP Servers for available tax types
|
188
|
+
def getTaxTypes
|
189
|
+
executeRequest("FEParamGetTiposTributos")["ResultGet"]["TributoTipo"]
|
190
|
+
end
|
191
|
+
|
192
|
+
# Asks to web service for servers status
|
193
|
+
def getServerStatus
|
194
|
+
executeRequest("FEDummy")
|
195
|
+
end
|
196
|
+
|
197
|
+
# Change date from AFIP used format (yyyymmdd) to yyyy-mm-dd
|
198
|
+
def formatDate(date)
|
199
|
+
m = /(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})/.match(date.to_s)
|
200
|
+
|
201
|
+
"#{m[:year]}-#{m[:month]}-#{m[:day]}"
|
202
|
+
end
|
203
|
+
|
204
|
+
# Sends request to AFIP servers
|
205
|
+
def executeRequest(operation, params = {})
|
206
|
+
params.merge!(getWSInitialRequest(operation))
|
207
|
+
|
208
|
+
results = super(operation, params)
|
209
|
+
|
210
|
+
checkErrors(operation, results)
|
211
|
+
|
212
|
+
results["#{operation}Result"]
|
213
|
+
end
|
214
|
+
|
215
|
+
# Prepare default request parameters for most operations
|
216
|
+
def getWSInitialRequest(operation)
|
217
|
+
if operation == "FEDummy"
|
218
|
+
{}
|
219
|
+
else
|
220
|
+
ta = getTokenAuthorization
|
221
|
+
|
222
|
+
{
|
223
|
+
"Auth": {
|
224
|
+
"Token": ta["token"],
|
225
|
+
"Sign": ta["sign"],
|
226
|
+
"Cuit": afip.CUIT
|
227
|
+
}
|
228
|
+
}
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Check if occurs an error on Web Service request
|
233
|
+
def checkErrors(operation, results)
|
234
|
+
res = results["#{operation}Result"]
|
235
|
+
|
236
|
+
if operation == "FECAESolicitar" && res["FeDetResp"]
|
237
|
+
if res["FeDetResp"]["FECAEDetResponse"].is_a?(Array)
|
238
|
+
res["FeDetResp"]["FECAEDetResponse"] = res["FeDetResp"]["FECAEDetResponse"][0]
|
239
|
+
end
|
240
|
+
|
241
|
+
if res["FeDetResp"]["FECAEDetResponse"]["Observaciones"] && res["FeDetResp"]["FECAEDetResponse"]["Resultado"] != "A"
|
242
|
+
res["Errors"] = { "Err" => res["FeDetResp"]["FECAEDetResponse"]["Observaciones"]["Obs"] }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
return unless res["Errors"]
|
247
|
+
|
248
|
+
err = res["Errors"]["Err"].is_a?(Array) ? res["Errors"]["Err"][0] : res["Errors"]["Err"]
|
249
|
+
|
250
|
+
raise "(#{err["Code"]}) #{err["Msg"]}"
|
251
|
+
end
|
252
|
+
|
253
|
+
private :checkErrors
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Afip
|
4
|
+
module WebServices
|
5
|
+
class RegisterInscriptionProof < Afip::WebService
|
6
|
+
@soapv12 = false
|
7
|
+
@WSDL = "https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA5?WSDL"
|
8
|
+
@URL = "https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA5"
|
9
|
+
@WSDL_TEST = "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA5?WSDL"
|
10
|
+
@URL_TEST = "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA5"
|
11
|
+
|
12
|
+
def initialize(afip)
|
13
|
+
super(afip, { "service": "ws_sr_constancia_inscripcion" })
|
14
|
+
end
|
15
|
+
|
16
|
+
# Asks to web service for taxpayer details
|
17
|
+
def getTaxpayerDetails(identifier)
|
18
|
+
# Get token and sign
|
19
|
+
ta = getTokenAuthorization
|
20
|
+
|
21
|
+
# Prepare params
|
22
|
+
params = {
|
23
|
+
"token": ta["token"],
|
24
|
+
"sign": ta["sign"],
|
25
|
+
"cuitRepresentada": afip.CUIT,
|
26
|
+
"idPersona": identifier
|
27
|
+
}
|
28
|
+
|
29
|
+
executeRequest("getPersona_v2", params)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Asks to web service for taxpayers details
|
33
|
+
def getTaxpayersDetails(identifiers)
|
34
|
+
# Get token and sign
|
35
|
+
ta = getTokenAuthorization
|
36
|
+
|
37
|
+
# Prepare params
|
38
|
+
params = {
|
39
|
+
"token": ta["token"],
|
40
|
+
"sign": ta["sign"],
|
41
|
+
"cuitRepresentada": afip.CUIT,
|
42
|
+
"idPersona": identifiers
|
43
|
+
}
|
44
|
+
|
45
|
+
executeRequest("getPersonaList_v2", params)["persona"]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Asks to web service for servers status
|
49
|
+
def getServerStatus
|
50
|
+
executeRequest("dummy")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Send request to AFIP servers
|
54
|
+
def executeRequest(operation, params = {})
|
55
|
+
results = super(operation, params)
|
56
|
+
|
57
|
+
if operation == "getPersona_v2"
|
58
|
+
results["personaReturn"]
|
59
|
+
elsif operation == "getPersonaList_v2"
|
60
|
+
results["personaListReturn"]
|
61
|
+
else
|
62
|
+
results["return"]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Afip
|
4
|
+
module WebServices
|
5
|
+
class RegisterScopeTen < Afip::WebService
|
6
|
+
@soapv12 = false
|
7
|
+
@WSDL = "https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA10?WSDL"
|
8
|
+
@URL = "https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA10"
|
9
|
+
@WSDL_TEST = "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA10?WSDL"
|
10
|
+
@URL_TEST = "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA10"
|
11
|
+
|
12
|
+
def initialize(afip)
|
13
|
+
super(afip, { "service": "ws_sr_padron_a10" })
|
14
|
+
end
|
15
|
+
|
16
|
+
# Asks to web service for taxpayer details
|
17
|
+
def getTaxpayerDetails(identifier)
|
18
|
+
# Get token and sign
|
19
|
+
ta = getTokenAuthorization
|
20
|
+
|
21
|
+
# Prepare params
|
22
|
+
params = {
|
23
|
+
"token": ta["token"],
|
24
|
+
"sign": ta["sign"],
|
25
|
+
"cuitRepresentada": afip.CUIT,
|
26
|
+
"idPersona": identifier
|
27
|
+
}
|
28
|
+
|
29
|
+
executeRequest("getPersona", params)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Asks to web service for servers status
|
33
|
+
def getServerStatus
|
34
|
+
executeRequest("dummy")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Send request to AFIP servers
|
38
|
+
def executeRequest(operation, params = {})
|
39
|
+
results = super(operation, params)
|
40
|
+
|
41
|
+
if operation == "getPersona"
|
42
|
+
results["personaReturn"]
|
43
|
+
else
|
44
|
+
results["return"]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Afip
|
4
|
+
module WebServices
|
5
|
+
class RegisterScopeThirteen < Afip::WebService
|
6
|
+
@soapv12 = false
|
7
|
+
@WSDL = "https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA13?WSDL"
|
8
|
+
@URL = "https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA13"
|
9
|
+
@WSDL_TEST = "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA13?WSDL"
|
10
|
+
@URL_TEST = "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA13"
|
11
|
+
|
12
|
+
def initialize(afip)
|
13
|
+
super(afip, { "service": "ws_sr_padron_a13" })
|
14
|
+
end
|
15
|
+
|
16
|
+
# Asks to web service for taxpayer details
|
17
|
+
def getTaxpayerDetails(identifier)
|
18
|
+
# Get token and sign
|
19
|
+
ta = getTokenAuthorization
|
20
|
+
|
21
|
+
# Prepare params
|
22
|
+
params = {
|
23
|
+
"token": ta["token"],
|
24
|
+
"sign": ta["sign"],
|
25
|
+
"cuitRepresentada": afip.CUIT,
|
26
|
+
"idPersona": identifier
|
27
|
+
}
|
28
|
+
|
29
|
+
executeRequest("getPersona", params)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Asks to web service for tax id by document number
|
33
|
+
def getTaxIDByDocument(document_number)
|
34
|
+
# Get token and sign
|
35
|
+
ta = getTokenAuthorization
|
36
|
+
|
37
|
+
# Prepare params
|
38
|
+
params = {
|
39
|
+
"token": ta["token"],
|
40
|
+
"sign": ta["sign"],
|
41
|
+
"cuitRepresentada": afip.CUIT,
|
42
|
+
"documento": document_number
|
43
|
+
}
|
44
|
+
|
45
|
+
executeRequest("getIdPersonaListByDocumento", params)["idPersona"]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Asks to web service for servers status
|
49
|
+
def getServerStatus
|
50
|
+
executeRequest("dummy")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Send request to AFIP servers
|
54
|
+
def executeRequest(operation, params = {})
|
55
|
+
results = super(operation, params)
|
56
|
+
|
57
|
+
if operation == "getPersona"
|
58
|
+
results["personaReturn"]
|
59
|
+
elsif operation == "getIdPersonaListByDocumento"
|
60
|
+
results["idPersonaListReturn"]
|
61
|
+
else
|
62
|
+
results["return"]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/afip/version.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Afip
|
4
|
+
class WebService
|
5
|
+
# Configurable options
|
6
|
+
attr_accessor :var, :soapv12, :WSDL, :URL, :WSDL_TEST, :URL_TEST, :afip, :options
|
7
|
+
|
8
|
+
def initialize(afip, options = {})
|
9
|
+
self.afip = afip
|
10
|
+
self.options = options
|
11
|
+
|
12
|
+
self.WSDL = options[:WSDL] if options.key?(:WSDL)
|
13
|
+
self.URL = options[:URL] if options.key?(:URL)
|
14
|
+
self.WSDL_TEST = options[:WSDL_TEST] if options.key?(:WSDL_TEST)
|
15
|
+
self.URL_TEST = options[:URL_TEST] if options.key?(:URL_TEST)
|
16
|
+
|
17
|
+
return unless options.key?(:generic) && options[:generic] == true
|
18
|
+
|
19
|
+
raise "service field is required in options" unless options.key?(:service)
|
20
|
+
|
21
|
+
options[:soapV1_2] = options.key?(:soapV1_2) ? options[:soapV1_2] : false
|
22
|
+
|
23
|
+
self.soapv12 = options[:soapV1_2]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Gets token authorization for an AFIP Web Service
|
27
|
+
#
|
28
|
+
# If force is true it forces to create a new TA
|
29
|
+
def getTokenAuthorization(force = false)
|
30
|
+
afip.getServiceTA(options[:service], force)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Sends request to AFIP servers
|
34
|
+
def executeRequest(method, params = {})
|
35
|
+
url = URI("https://app.afipsdk.com/api/v1/afip/requests")
|
36
|
+
|
37
|
+
https = Net::HTTP.new(url.host, url.port)
|
38
|
+
https.use_ssl = true
|
39
|
+
|
40
|
+
request = Net::HTTP::Post.new(url)
|
41
|
+
request["Content-Type"] = "application/json"
|
42
|
+
request["sdk-version-number"] = Afip::VERSION
|
43
|
+
request["sdk-library"] = "ruby"
|
44
|
+
request["sdk-environment"] = afip.production == true ? "prod" : "dev"
|
45
|
+
request["Authorization"] = "Bearer #{afip.access_token}" if afip.access_token
|
46
|
+
|
47
|
+
data = {
|
48
|
+
"method": method,
|
49
|
+
"params": params,
|
50
|
+
"environment": afip.production == true ? "prod" : "dev",
|
51
|
+
"wsid": options[:service],
|
52
|
+
"url": afip.production == true ? self.URL : self.URL_TEST,
|
53
|
+
"wsdl": afip.production == true ? self.WSDL : self.WSDL_TEST,
|
54
|
+
"soap_v_1_2": soapv12
|
55
|
+
}
|
56
|
+
|
57
|
+
request.body = JSON.dump(data)
|
58
|
+
response = https.request(request)
|
59
|
+
|
60
|
+
unless response.is_a? Net::HTTPSuccess
|
61
|
+
begin
|
62
|
+
raise JSON.parse(response.read_body)
|
63
|
+
rescue
|
64
|
+
raise response.read_body
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
JSON.parse(response.read_body)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/afip.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
require "uri"
|
5
|
+
require "json"
|
6
|
+
require "net/http"
|
7
|
+
|
8
|
+
require_relative "afip/version"
|
9
|
+
require_relative "afip/web_service"
|
10
|
+
require_relative "afip/electronic_billing"
|
11
|
+
require_relative "afip/register_inscription_proof"
|
12
|
+
require_relative "afip/register_scope_ten"
|
13
|
+
require_relative "afip/register_scope_thirteen"
|
14
|
+
|
15
|
+
# AfipSDK is the easyest way to connect with AFIP
|
16
|
+
module Afip
|
17
|
+
def self.new(options)
|
18
|
+
Afip::Instance.new(options)
|
19
|
+
end
|
20
|
+
|
21
|
+
class Instance
|
22
|
+
attr_accessor :CUIT,
|
23
|
+
:cert,
|
24
|
+
:key,
|
25
|
+
:production,
|
26
|
+
:access_token,
|
27
|
+
:ElectronicBilling,
|
28
|
+
:RegisterInscriptionProof,
|
29
|
+
:RegisterScopeTen,
|
30
|
+
:RegisterScopeThirteen
|
31
|
+
|
32
|
+
def initialize(options)
|
33
|
+
raise "CUIT field is required in options" unless options.key?(:CUIT)
|
34
|
+
|
35
|
+
self.CUIT = options[:CUIT]
|
36
|
+
self.production = options.key?(:production) ? options[:production] : false
|
37
|
+
self.cert = options[:cert]
|
38
|
+
self.key = options[:key]
|
39
|
+
self.access_token = options[:access_token]
|
40
|
+
|
41
|
+
self.ElectronicBilling = Afip::WebServices::ElectronicBilling.new(self)
|
42
|
+
self.RegisterInscriptionProof = Afip::WebServices::RegisterInscriptionProof.new(self)
|
43
|
+
self.RegisterScopeTen = Afip::WebServices::RegisterScopeTen.new(self)
|
44
|
+
self.RegisterScopeThirteen = Afip::WebServices::RegisterScopeThirteen.new(self)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Gets token authorization for an AFIP Web Service
|
48
|
+
#
|
49
|
+
# If force is true it forces to create a new TA
|
50
|
+
def getServiceTA(service, force = false)
|
51
|
+
url = URI("https://app.afipsdk.com/api/v1/afip/auth")
|
52
|
+
|
53
|
+
https = Net::HTTP.new(url.host, url.port)
|
54
|
+
https.use_ssl = true
|
55
|
+
|
56
|
+
request = Net::HTTP::Post.new(url)
|
57
|
+
request["Content-Type"] = "application/json"
|
58
|
+
request["sdk-version-number"] = Afip::VERSION
|
59
|
+
request["sdk-library"] = "ruby"
|
60
|
+
request["sdk-environment"] = production == true ? "prod" : "dev"
|
61
|
+
request["Authorization"] = "Bearer #{access_token}" if access_token
|
62
|
+
|
63
|
+
data = {
|
64
|
+
"environment": production == true ? "prod" : "dev",
|
65
|
+
"tax_id": self.CUIT,
|
66
|
+
"wsid": service,
|
67
|
+
"force_create": force
|
68
|
+
}
|
69
|
+
|
70
|
+
data["cert"] = cert if cert
|
71
|
+
data["key"] = key if key
|
72
|
+
|
73
|
+
request.body = JSON.dump(data)
|
74
|
+
response = https.request(request)
|
75
|
+
|
76
|
+
unless response.is_a? Net::HTTPSuccess
|
77
|
+
begin
|
78
|
+
raise JSON.parse(response.read_body)
|
79
|
+
rescue
|
80
|
+
raise response.read_body
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
JSON.parse(response.read_body)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Get last request and last response XML
|
88
|
+
def getLastRequestXML
|
89
|
+
url = URI("https://app.afipsdk.com/api/v1/afip/requests/last-xml")
|
90
|
+
|
91
|
+
https = Net::HTTP.new(url.host, url.port)
|
92
|
+
https.use_ssl = true
|
93
|
+
|
94
|
+
request = Net::HTTP::Get.new(url)
|
95
|
+
request["sdk-version-number"] = Afip::VERSION
|
96
|
+
request["sdk-library"] = "ruby"
|
97
|
+
request["sdk-environment"] = production == true ? "prod" : "dev"
|
98
|
+
request["Authorization"] = "Bearer #{access_token}" if access_token
|
99
|
+
|
100
|
+
data["cert"] = cert if cert
|
101
|
+
data["key"] = key if key
|
102
|
+
|
103
|
+
response = https.request(request)
|
104
|
+
|
105
|
+
unless response.is_a? Net::HTTPSuccess
|
106
|
+
begin
|
107
|
+
raise JSON.parse(response.read_body)
|
108
|
+
rescue
|
109
|
+
raise response.read_body
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
JSON.parse(response.read_body)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Create generic Web Service
|
117
|
+
def webService(service, options = {})
|
118
|
+
options[:service] = service
|
119
|
+
options[:generic] = true
|
120
|
+
|
121
|
+
Afip::WebService.new(self, options)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/sig/afip.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: afip.rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Afip SDK
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-12-26 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: AfipSDK is the easyest way to connect with AFIP
|
14
|
+
email:
|
15
|
+
- afipsdk@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".rubocop.yml"
|
21
|
+
- LICENSE.txt
|
22
|
+
- README.md
|
23
|
+
- Rakefile
|
24
|
+
- afip.gemspec
|
25
|
+
- lib/afip.rb
|
26
|
+
- lib/afip/electronic_billing.rb
|
27
|
+
- lib/afip/register_inscription_proof.rb
|
28
|
+
- lib/afip/register_scope_ten.rb
|
29
|
+
- lib/afip/register_scope_thirteen.rb
|
30
|
+
- lib/afip/version.rb
|
31
|
+
- lib/afip/web_service.rb
|
32
|
+
- sig/afip.rbs
|
33
|
+
homepage: https://afipsdk.com
|
34
|
+
licenses:
|
35
|
+
- MIT
|
36
|
+
metadata:
|
37
|
+
homepage_uri: https://afipsdk.com
|
38
|
+
source_code_uri: https://github.com/AfipSDK/afip.rb
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.3.0
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubygems_version: 3.1.2
|
55
|
+
signing_key:
|
56
|
+
specification_version: 4
|
57
|
+
summary: Library to connect with AFIP
|
58
|
+
test_files: []
|