Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e590462
Added opciones to comprobante_to_request method to merge periodo_asoc…
martinnicolas Nov 13, 2024
7a12804
Minor fix to tests
martinnicolas Nov 14, 2024
0b5bd4d
Add WSFEX support for export invoices
cuestalvaro Apr 15, 2026
6340806
Fix error request WSFEX
cuestalvaro Apr 17, 2026
9efcaa0
Fix request payloads
cuestalvaro Apr 17, 2026
31a2334
Fix required fields
cuestalvaro Apr 17, 2026
3dd9288
Update urls and fix fixture
cuestalvaro Apr 17, 2026
1940e30
Align WSFEX validations with v3.1.1
cuestalvaro Apr 17, 2026
04e963b
Enhance WSFEX response fixtures with additional fields and error hand…
cuestalvaro Apr 22, 2026
5ce9672
Compact nils in WSFEX before marshalling
cuestalvaro May 21, 2026
f467b6a
Clarify `id` field description in WSFEX authorization payload require…
cuestalvaro May 21, 2026
8e0d02f
Refactor observaciones handling in WSFEX to simplify response structure
cuestalvaro May 21, 2026
a5df76b
Extraer constantes para valores en WSFEX
cuestalvaro May 21, 2026
9a33d16
Clarify `moneda_ctz` requirement in WSFEX authorization payload
cuestalvaro May 21, 2026
d7ba6b2
Move private method declaration for clarity in WSFEX class
cuestalvaro May 22, 2026
1e9cb26
Add automatic `id` assignment from `cbte_nro` in WSFEX authorization …
cuestalvaro May 22, 2026
09ac27e
Fix README.md
cuestalvaro May 22, 2026
ecac063
Ensure 'Permiso_existente' defaults to an empty string if not provide…
cuestalvaro May 29, 2026
c099433
Merge pull request #4 from cristianrennella/add-wsfex
ansilva1991 Jun 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
rexml (3.3.1)
strscan
rexml (3.3.9)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
Expand All @@ -144,7 +143,6 @@ GEM
nori (~> 2.4)
wasabi (>= 3.7, < 6)
shellany (0.0.1)
strscan (3.1.0)
thor (1.3.1)
timeout (0.4.1)
tzinfo (2.0.6)
Expand Down
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Ruby client para los web services de la AFIP.

- wsaa (WSAA)
- wsfe (WSFE)
- wsfex (WSFEX)
- ws_sr_constancia_inscripcion (WSConstanciaInscripcion)
- ws_sr_padron_a100 (PersonaServiceA100)
- ws_sr_padron_a4 (PersonaServiceA4)
Expand All @@ -32,6 +33,68 @@ ws = Afipws::WSFE.new env: :development, cuit: '...', key: File.read('test.key')
puts ws.cotizacion 'DOL'
```

Para comprobantes de exportación (`Factura E`) se puede usar `Afipws::WSFEX`. Internamente autentica con `WSAA` usando `service: 'wsfex'`.

```ruby
require 'afipws'

ws = Afipws::WSFEX.new env: :development, cuit: '...', key: File.read('test.key'), cert: File.read('test.crt')
ultimo = ws.ultimo_comprobante_autorizado(pto_vta: 3, cbte_tipo: 19)

rta = ws.autorizar_comprobantes(
pto_vta: 3,
cbte_tipo: 19,
comprobantes: [
{
cbte_nro: ultimo + 1,
fecha_cbte: Date.today,
tipo_expo: 2,
permiso_existente: 'N',
dst_cmp: 200,
cliente: 'Cliente del exterior',
cuit_pais_cliente: 55_555_555_555,
domicilio_cliente: 'Rua Falsa 123',
moneda_id: 'DOL',
moneda_ctz: 1,
imp_total: 121.0,
idioma_cbte: 1,
items: [
{ pro_ds: 'Servicio mensual', pro_umed: 7, pro_total_item: 121.0 }
]
}
]
)
```

`WSFEX` expone actualmente estos métodos:

- `ultimo_comprobante_autorizado(opciones)`
- `autorizar_comprobantes(opciones)`

Para `autorizar_comprobantes`, el payload mínimo sigue la estructura documentada por AFIP para `FEXAuthorize`. A nivel comprobante se validan como obligatorios:

- `id` (se completa automáticamente con `cbte_nro` si no se envía)
- `cbte_tipo`
- `punto_vta`
- `cbte_nro`
- `tipo_expo`
- `permiso_existente` (requerido sólo para `cbte_tipo=19` y `tipo_expo=1`; vacío en otros casos)
- `dst_cmp`
- `cliente`
- `domicilio_cliente`
- `moneda_id`
- `moneda_ctz` (no requerido si `can_mis_mon_ext` es `'S'`; debe ser mayor a 0)
- `imp_total`
- `idioma_cbte`
- `items`
- `cuit_pais_cliente` o `id_impositivo`

Cada item requiere al menos:

- `pro_ds`
- `pro_umed`
- `pro_total_item`

Ver specs para más ejemplos.

## Contributing
Expand Down
1 change: 1 addition & 0 deletions lib/afipws.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module Afipws
require 'afipws/client'
require 'afipws/wsaa'
require 'afipws/wsfe'
require 'afipws/wsfex'
require 'afipws/ws_constancia_inscripcion'
require 'afipws/persona_service_a4'
require 'afipws/persona_service_a5'
Expand Down
11 changes: 7 additions & 4 deletions lib/afipws/wsfe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def autorizar_comprobantes opciones
'FeCAEReq' => {
'FeCabReq' => opciones.select_keys(:cbte_tipo, :pto_vta).merge(cant_reg: comprobantes.size),
'FeDetReq' => {
'FECAEDetRequest' => comprobantes.map { |comprobante| comprobante_to_request comprobante }
'FECAEDetRequest' => comprobantes.map { |comprobante| comprobante_to_request(comprobante, opciones) }
}
}
}
Expand All @@ -83,11 +83,14 @@ def autorizar_comprobantes opciones
x2r r, cae_fch_vto: :date, fch_serv_desde: :date, fch_serv_hasta: :date, fch_vto_pago: :date, cbte_nro: :integer, code: :integer
end

def comprobante_to_request comprobante
def comprobante_to_request(comprobante, opciones)
nro = comprobante.delete :cbte_nro
iva = comprobante.delete :imp_iva
comprobante.delete :tributos if comprobante[:imp_trib] == 0
comprobante.merge cbte_desde: nro, cbte_hasta: nro, 'ImpIVA' => iva
comprobante.merge! cbte_desde: nro, cbte_hasta: nro, 'ImpIVA' => iva
comprobante.merge! periodo_asoc: opciones[:periodo_asoc] if opciones[:periodo_asoc]

comprobante
end

def solicitar_caea
Expand All @@ -111,7 +114,7 @@ def informar_comprobantes_caea opciones
'FeCabReq' => opciones.select_keys(:cbte_tipo, :pto_vta).merge(cant_reg: comprobantes.size),
'FeDetReq' => {
'FECAEADetRequest' => comprobantes.map do |comprobante|
comprobante_to_request comprobante.merge('CAEA' => comprobante.delete(:caea))
comprobante_to_request(comprobante.merge('CAEA' => comprobante.delete(:caea)), opciones)
end
}
}
Expand Down
Loading