snoopy_afip 4.3.0 → 4.3.1
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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +31 -0
- data/.github/workflows/release.yml +33 -0
- data/AGENTS.md +100 -0
- data/CHANGELOG.md +44 -0
- data/CLAUDE.md +15 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +68 -19
- data/README.md +87 -189
- data/docs/behavior/behavior.md +84 -0
- data/docs/config/configuracion.md +94 -0
- data/docs/consumed/afip.md +61 -0
- data/docs/errors/errors.md +69 -0
- data/docs/glossary/glossary.md +74 -0
- data/docs/interface/interface.md +86 -0
- data/docs/test/testing.md +74 -0
- data/docs/topology/topology.md +44 -0
- data/lib/snoopy_afip/authorize_adapter.rb +5 -5
- data/lib/snoopy_afip/exceptions.rb +12 -0
- data/lib/snoopy_afip/version.rb +1 -1
- data/lib/snoopy_afip.rb +0 -4
- data/skill/SKILL.md +72 -0
- data/skills.yml +17 -0
- data/snoopy_afip.gemspec +5 -3
- data/spec/snoopy_afip/authentication_adapter_spec.rb +20 -0
- data/spec/snoopy_afip/authorize_adapter_spec.rb +37 -0
- data/spec/snoopy_afip/bill_spec.rb +66 -83
- data/spec/snoopy_afip/exceptions_spec.rb +27 -0
- data/spec/spec_helper.rb +16 -20
- metadata +56 -7
- data/CHANGELOG +0 -27
- data/spec/snoopy_afip/authorizer_spec.rb +0 -9
|
@@ -1,106 +1,89 @@
|
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) +
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
|
2
|
+
|
|
3
|
+
RSpec.describe Snoopy::Bill do
|
|
4
|
+
def valid_attrs(overrides = {})
|
|
5
|
+
{
|
|
6
|
+
cuit: "20111111112",
|
|
7
|
+
sale_point: "0001",
|
|
8
|
+
total_net: 100.0,
|
|
9
|
+
concept: "Productos",
|
|
10
|
+
document_type: "CUIT",
|
|
11
|
+
document_num: "30710151543",
|
|
12
|
+
issuer_iva_cond: Snoopy::RESPONSABLE_INSCRIPTO,
|
|
13
|
+
receiver_iva_cond: :factura_a,
|
|
14
|
+
receiver_iva_condition: :responsable_inscripto,
|
|
15
|
+
currency: :peso,
|
|
16
|
+
service_date_from: "20240101",
|
|
17
|
+
service_date_to: "20240131",
|
|
18
|
+
alicivas: [{ id: 0.21, amount: 21.0, taxeable_base: 100.0 }]
|
|
19
|
+
}.merge(overrides)
|
|
20
|
+
end
|
|
2
21
|
|
|
3
|
-
describe "
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
["CantReg", "CbteTipo", "PtoVta"].each do |key|
|
|
8
|
-
@header.has_key?(key).should == true
|
|
22
|
+
describe "#cbte_type" do
|
|
23
|
+
it "deriva el código del comprobante desde receiver_iva_cond" do
|
|
24
|
+
expect(described_class.new(valid_attrs).cbte_type).to eq("01") # BILL_TYPE[:factura_a]
|
|
25
|
+
expect(described_class.new(valid_attrs(receiver_iva_cond: :factura_b)).cbte_type).to eq("06")
|
|
9
26
|
end
|
|
10
27
|
end
|
|
11
28
|
|
|
12
|
-
describe "
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
["Token", "Sign", "Cuit"].each do |key|
|
|
18
|
-
@bill.body["Auth"][key].should_not == nil
|
|
19
|
-
end
|
|
20
|
-
@bill.documento.should == Snoopy.default_documento
|
|
21
|
-
@bill.moneda.should == Snoopy.default_moneda
|
|
29
|
+
describe "#iva_sum y #total" do
|
|
30
|
+
it "suma las alícuotas y calcula el total neto + IVA" do
|
|
31
|
+
bill = described_class.new(valid_attrs)
|
|
32
|
+
expect(bill.iva_sum).to eq(21.0)
|
|
33
|
+
expect(bill.total).to eq(121.0)
|
|
22
34
|
end
|
|
23
35
|
|
|
24
|
-
it "
|
|
25
|
-
|
|
26
|
-
@bill.cbte_type.should == "01"
|
|
36
|
+
it "total es 0 cuando el neto es 0" do
|
|
37
|
+
expect(described_class.new(valid_attrs(total_net: 0)).total).to eq(0)
|
|
27
38
|
end
|
|
39
|
+
end
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
describe "#exchange_rate" do
|
|
42
|
+
it "es 1 para pesos" do
|
|
43
|
+
expect(described_class.new(valid_attrs(currency: :peso)).exchange_rate).to eq(1)
|
|
32
44
|
end
|
|
45
|
+
end
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
expect
|
|
47
|
+
describe "#receiver_iva_condition_id" do
|
|
48
|
+
it "mapea la condición de IVA del receptor (RG 5616)" do
|
|
49
|
+
expect(described_class.new(valid_attrs).receiver_iva_condition_id).to eq("1")
|
|
50
|
+
expect(described_class.new(valid_attrs(receiver_iva_condition: :consumidor_final)).receiver_iva_condition_id).to eq("5")
|
|
37
51
|
end
|
|
38
52
|
|
|
39
|
-
it "
|
|
40
|
-
|
|
41
|
-
@bill.exchange_rate.to_i.should be > 0
|
|
53
|
+
it "es '' cuando no se informó la condición" do
|
|
54
|
+
expect(described_class.new(valid_attrs(receiver_iva_condition: nil)).receiver_iva_condition_id).to eq("")
|
|
42
55
|
end
|
|
56
|
+
end
|
|
43
57
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
58
|
+
describe "estado del resultado" do
|
|
59
|
+
it "refleja el veredicto de AFIP" do
|
|
60
|
+
bill = described_class.new(valid_attrs)
|
|
61
|
+
bill.result = "A"
|
|
62
|
+
expect(bill.approved?).to be(true)
|
|
63
|
+
bill.result = "R"
|
|
64
|
+
expect(bill.rejected?).to be(true)
|
|
65
|
+
bill.result = "P"
|
|
66
|
+
expect(bill.partial_approved?).to be(true)
|
|
47
67
|
end
|
|
68
|
+
end
|
|
48
69
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@bill.iva_sum.should be_within(0.05).of(21.18)
|
|
56
|
-
@bill.total.should be_within(0.05).of(122.07)
|
|
70
|
+
describe "#valid?" do
|
|
71
|
+
it "es válido con atributos completos y correctos" do
|
|
72
|
+
bill = described_class.new(valid_attrs)
|
|
73
|
+
expect(bill.valid?).to be(true)
|
|
74
|
+
expect(bill.errors).to be_empty
|
|
57
75
|
end
|
|
58
76
|
|
|
59
|
-
it "
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@bill.iva_cond = :responsable_inscripto
|
|
64
|
-
@bill.concepto = "Servicios"
|
|
65
|
-
|
|
66
|
-
@bill.setup_bill
|
|
67
|
-
|
|
68
|
-
detail = @bill.body["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
|
|
69
|
-
|
|
70
|
-
detail["FchServDesde"].should == Time.new.strftime('%Y%m%d')
|
|
71
|
-
detail["FchServHasta"].should == Time.new.strftime('%Y%m%d')
|
|
72
|
-
detail["FchVtoPago"].should == Time.new.strftime('%Y%m%d')
|
|
73
|
-
|
|
74
|
-
@bill.due_date = Date.new(2011, 12, 10).strftime('%Y%m%d')
|
|
75
|
-
@bill.fch_serv_desde = Date.new(2011, 11, 01).strftime('%Y%m%d')
|
|
76
|
-
@bill.fch_serv_hasta = Date.new(2011, 11, 30).strftime('%Y%m%d')
|
|
77
|
-
|
|
78
|
-
@bill.setup_bill
|
|
79
|
-
|
|
80
|
-
detail = @bill.body["FeCAEReq"]["FeDetReq"]["FECAEDetRequest"]
|
|
81
|
-
|
|
82
|
-
detail["FchServDesde"].should == "20111101"
|
|
83
|
-
detail["FchServHasta"].should == "20111130"
|
|
84
|
-
detail["FchVtoPago"].should == "20111210"
|
|
77
|
+
it "marca currency inválida" do
|
|
78
|
+
bill = described_class.new(valid_attrs(currency: :yen))
|
|
79
|
+
expect(bill.valid?).to be(false)
|
|
80
|
+
expect(bill.errors).to have_key(:currency)
|
|
85
81
|
end
|
|
86
82
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
@bill.doc_num = "30710151543"
|
|
92
|
-
@bill.iva_cond = target_iva_cond
|
|
93
|
-
@bill.concepto = "Servicios"
|
|
94
|
-
|
|
95
|
-
@bill.authorized?.should == false
|
|
96
|
-
@bill.authorize.should == true
|
|
97
|
-
@bill.authorized?.should == true
|
|
98
|
-
|
|
99
|
-
response = @bill.response
|
|
100
|
-
|
|
101
|
-
response.length.should == 28
|
|
102
|
-
response.cae.length.should == 14
|
|
103
|
-
end
|
|
83
|
+
it "marca document_type inválido" do
|
|
84
|
+
bill = described_class.new(valid_attrs(document_type: "NOPE"))
|
|
85
|
+
bill.valid?
|
|
86
|
+
expect(bill.errors).to have_key(:document_type)
|
|
104
87
|
end
|
|
105
88
|
end
|
|
106
89
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
|
2
|
+
|
|
3
|
+
RSpec.describe Snoopy::Exception do
|
|
4
|
+
# Regresión #14: ServerTimeout debe seguir siendo un Timeout::Error (compat
|
|
5
|
+
# hacia atrás) y a la vez quedar bajo el paraguas Snoopy::Exception::Error.
|
|
6
|
+
describe "jerarquía de ServerTimeout" do
|
|
7
|
+
subject(:ancestors) { Snoopy::Exception::ServerTimeout.ancestors }
|
|
8
|
+
|
|
9
|
+
it "sigue siendo un Timeout::Error" do
|
|
10
|
+
expect(ancestors).to include(Timeout::Error)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "queda bajo el paraguas Snoopy::Exception::Error" do
|
|
14
|
+
expect(ancestors).to include(Snoopy::Exception::Error)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "el paraguas Error cubre también a las excepciones de la base" do
|
|
19
|
+
expect(Snoopy::Exception::ClientError.ancestors).to include(Snoopy::Exception::Error)
|
|
20
|
+
expect(Snoopy::Exception::AuthorizeAdapter::BuildBodyRequest.ancestors).to include(Snoopy::Exception::Error)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "un rescue del paraguas atrapa tanto el timeout como los errores de cliente" do
|
|
24
|
+
expect { raise Snoopy::Exception::ServerTimeout }.to raise_error(Snoopy::Exception::Error)
|
|
25
|
+
expect { raise Snoopy::Exception::ClientError.new("x") }.to raise_error(Snoopy::Exception::Error)
|
|
26
|
+
end
|
|
27
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
require 'snoopy'
|
|
3
|
-
require 'rspec'
|
|
4
|
-
require 'ruby-debug'
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
require "snoopy_afip"
|
|
4
|
+
# Bill#valid? usa blank?/present? (ActiveSupport); en producción lo provee Rails.
|
|
5
|
+
require "active_support/core_ext/object/blank"
|
|
6
|
+
require "rspec"
|
|
9
7
|
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
|
|
8
|
+
# Config base de homologación para construir adapters en los specs.
|
|
9
|
+
# Nunca credenciales reales: pkey/cert/cuit son placeholders de prueba.
|
|
10
|
+
Snoopy.auth_url = "https://wsaahomo.afip.gov.ar/ws/services/LoginCms?wsdl"
|
|
11
|
+
Snoopy.service_url = "https://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL"
|
|
12
|
+
Snoopy.default_currency = :peso
|
|
13
|
+
Snoopy.default_concept = "Productos"
|
|
14
|
+
Snoopy.default_document_type = "CUIT"
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Snoopy.auth_url = "https://wsaahomo.afip.gov.ar/ws/services/LoginCms"
|
|
19
|
-
Snoopy.service_url = "http://wswhomo.afip.gov.ar/wsfev1/service.asmx?WSDL"
|
|
20
|
-
Snoopy.default_concepto = "Productos y Servicios"
|
|
21
|
-
Snoopy.default_documento = "CUIT"
|
|
22
|
-
Snoopy.default_moneda = :peso
|
|
23
|
-
Snoopy.own_iva_cond = :responsable_inscripto
|
|
16
|
+
RSpec.configure do |config|
|
|
17
|
+
config.expect_with(:rspec) { |e| e.syntax = :expect }
|
|
18
|
+
config.disable_monkey_patching!
|
|
19
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: snoopy_afip
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.3.
|
|
4
|
+
version: 4.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- g.edera
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-06-29 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: savon
|
|
@@ -23,6 +24,34 @@ dependencies:
|
|
|
23
24
|
- - "~>"
|
|
24
25
|
- !ruby/object:Gem::Version
|
|
25
26
|
version: 2.12.1
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.13'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.13'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: activesupport
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
26
55
|
description: Adaptador para Web Service de Facturación Electrónica Argentina (AFIP)
|
|
27
56
|
email: gab.edera@gmail.com
|
|
28
57
|
executables: []
|
|
@@ -30,8 +59,12 @@ extensions: []
|
|
|
30
59
|
extra_rdoc_files: []
|
|
31
60
|
files:
|
|
32
61
|
- ".document"
|
|
62
|
+
- ".github/workflows/main.yml"
|
|
63
|
+
- ".github/workflows/release.yml"
|
|
33
64
|
- ".gitignore"
|
|
34
|
-
-
|
|
65
|
+
- AGENTS.md
|
|
66
|
+
- CHANGELOG.md
|
|
67
|
+
- CLAUDE.md
|
|
35
68
|
- Gemfile
|
|
36
69
|
- Gemfile.lock
|
|
37
70
|
- LICENSE.txt
|
|
@@ -40,6 +73,14 @@ files:
|
|
|
40
73
|
- Rakefile
|
|
41
74
|
- VERSION
|
|
42
75
|
- autotest/discover.rb
|
|
76
|
+
- docs/behavior/behavior.md
|
|
77
|
+
- docs/config/configuracion.md
|
|
78
|
+
- docs/consumed/afip.md
|
|
79
|
+
- docs/errors/errors.md
|
|
80
|
+
- docs/glossary/glossary.md
|
|
81
|
+
- docs/interface/interface.md
|
|
82
|
+
- docs/test/testing.md
|
|
83
|
+
- docs/topology/topology.md
|
|
43
84
|
- lib/snoopy_afip.rb
|
|
44
85
|
- lib/snoopy_afip/authentication_adapter.rb
|
|
45
86
|
- lib/snoopy_afip/authorize_adapter.rb
|
|
@@ -51,9 +92,13 @@ files:
|
|
|
51
92
|
- lib/snoopy_afip/core_ext/string.rb
|
|
52
93
|
- lib/snoopy_afip/exceptions.rb
|
|
53
94
|
- lib/snoopy_afip/version.rb
|
|
95
|
+
- skill/SKILL.md
|
|
96
|
+
- skills.yml
|
|
54
97
|
- snoopy_afip.gemspec
|
|
55
|
-
- spec/snoopy_afip/
|
|
98
|
+
- spec/snoopy_afip/authentication_adapter_spec.rb
|
|
99
|
+
- spec/snoopy_afip/authorize_adapter_spec.rb
|
|
56
100
|
- spec/snoopy_afip/bill_spec.rb
|
|
101
|
+
- spec/snoopy_afip/exceptions_spec.rb
|
|
57
102
|
- spec/spec_helper.rb
|
|
58
103
|
- wsaa-client.sh
|
|
59
104
|
- xds_login.xml
|
|
@@ -61,6 +106,7 @@ homepage: https://github.com/gedera/snoopy_afip
|
|
|
61
106
|
licenses:
|
|
62
107
|
- MIT
|
|
63
108
|
metadata: {}
|
|
109
|
+
post_install_message:
|
|
64
110
|
rdoc_options: []
|
|
65
111
|
require_paths:
|
|
66
112
|
- lib
|
|
@@ -68,17 +114,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
68
114
|
requirements:
|
|
69
115
|
- - ">="
|
|
70
116
|
- !ruby/object:Gem::Version
|
|
71
|
-
version: '
|
|
117
|
+
version: '2.5'
|
|
72
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
119
|
requirements:
|
|
74
120
|
- - ">="
|
|
75
121
|
- !ruby/object:Gem::Version
|
|
76
122
|
version: '0'
|
|
77
123
|
requirements: []
|
|
78
|
-
rubygems_version: 3.
|
|
124
|
+
rubygems_version: 3.4.19
|
|
125
|
+
signing_key:
|
|
79
126
|
specification_version: 4
|
|
80
127
|
summary: Adaptador AFIP wsfe.
|
|
81
128
|
test_files:
|
|
82
|
-
- spec/snoopy_afip/
|
|
129
|
+
- spec/snoopy_afip/authentication_adapter_spec.rb
|
|
130
|
+
- spec/snoopy_afip/authorize_adapter_spec.rb
|
|
83
131
|
- spec/snoopy_afip/bill_spec.rb
|
|
132
|
+
- spec/snoopy_afip/exceptions_spec.rb
|
|
84
133
|
- spec/spec_helper.rb
|
data/CHANGELOG
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
All notable changes to this project will be documented in this file.
|
|
3
|
-
|
|
4
|
-
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
5
|
-
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
|
-
|
|
7
|
-
## [3.0.2] - July 14, 2017
|
|
8
|
-
### Added
|
|
9
|
-
- `Cms Builder exception`.
|
|
10
|
-
|
|
11
|
-
## [3.0.0] - June 29, 2017
|
|
12
|
-
### Added
|
|
13
|
-
- `Authentication Class` destinada a la comunicación con el **WSAA**.
|
|
14
|
-
- `Authorize Class` destinada a la comunicación con el **WSFE**.
|
|
15
|
-
- `Client Class` destinada para crear el cliente de `Savon`.
|
|
16
|
-
- Mejor manejo de Exceptions.
|
|
17
|
-
- Validaciones en el modelo `Bill`.
|
|
18
|
-
|
|
19
|
-
### Changed
|
|
20
|
-
- Se pasó toda la logica de comunicación con el **WSFE** del modelo `Bill` al modelo `Authorize`.
|
|
21
|
-
- No se crea mas el rchivo para la clave privada, devuelve en RAW.
|
|
22
|
-
- No se crea mas un archivo para almacenar el _token_, _sign_, se devuelve en RAW.
|
|
23
|
-
- Evitar raisear si se logró autorizar una factura con el **WSFE**. Manejo en el errors del `Bill` o el `Authorize`.
|
|
24
|
-
|
|
25
|
-
### Removed
|
|
26
|
-
- Eliminiado modulo `AuthData`.
|
|
27
|
-
- Eliminado el uso de `Bash` para autenticar en el **WSAA**.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
|
-
|
|
3
|
-
describe "Authorizer" do
|
|
4
|
-
it "should read credentials on initialize" do
|
|
5
|
-
authorizer = Snoopy::Authorizer.new
|
|
6
|
-
authorizer.pkey.should == 'spec/fixtures/pkey'
|
|
7
|
-
authorizer.cert.should == 'spec/fixtures/cert.crt'
|
|
8
|
-
end
|
|
9
|
-
end
|