cobro_digital 1.8.0 → 1.9.0
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 +35 -0
- data/.github/workflows/release.yml +34 -0
- data/AGENTS.md +86 -0
- data/CHANGELOG.md +21 -0
- data/CLAUDE.md +15 -0
- data/README.md +96 -178
- data/cobro_digital.gemspec +7 -1
- data/docs/behavior/behavior.md +84 -0
- data/docs/config/configuracion.md +86 -0
- data/docs/consumed/cobrodigital.md +82 -0
- data/docs/glossary/glossary.md +101 -0
- data/docs/interface/interface.md +106 -0
- data/docs/test/testing.md +67 -0
- data/docs/topology/topology.md +42 -0
- data/lib/cobro_digital/version.rb +1 -1
- data/lib/cobro_digital.rb +38 -7
- data/skill/SKILL.md +87 -0
- data/skills.yml +17 -0
- metadata +36 -16
- data/.travis.yml +0 -4
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Comportamiento — cobro_digital
|
|
2
|
+
|
|
3
|
+
> meta: artefacto · RFC-007 · generado arch-enrich · anclado a v1.9.0 · cobertura: 2 flujos documentados; ausencia ≠ inexistencia
|
|
4
|
+
|
|
5
|
+
## 1. Resumen
|
|
6
|
+
|
|
7
|
+
Dos flujos cubren el comportamiento de la gema: la **operación simple** (construir → `call` → `parse_response`) y el **batch meta** (agrupar N operaciones en una llamada). Ambos terminan en el mismo transporte `Client#call`.
|
|
8
|
+
|
|
9
|
+
## Cobertura
|
|
10
|
+
|
|
11
|
+
| flujo | estado |
|
|
12
|
+
|---|---|
|
|
13
|
+
| operación simple (cualquier subclase de `Operador`) | **documentado** |
|
|
14
|
+
| batch `meta` | **documentado** |
|
|
15
|
+
| selección de transporte SOAP vs HTTPS (interno a `Client`) | **documentado** (en flujo 1) |
|
|
16
|
+
| manejo de error de transporte | parcial — propaga sin envolver (ver `docs/consumed §d`) |
|
|
17
|
+
|
|
18
|
+
## 2. Flujos
|
|
19
|
+
|
|
20
|
+
### 2.1 Operación simple
|
|
21
|
+
|
|
22
|
+
El consumidor construye una operación con un método de clase, la ejecuta con `#call(id, sid)` y decodifica con `#parse_response`. `Client#call` mergea el bloque de comercio (con handshake) y despacha al transporte elegido.
|
|
23
|
+
|
|
24
|
+
```mermaid
|
|
25
|
+
sequenceDiagram
|
|
26
|
+
actor Consumer
|
|
27
|
+
participant Op as Operador subclase
|
|
28
|
+
participant Cli as Client
|
|
29
|
+
participant WS as WS CobroDigital
|
|
30
|
+
|
|
31
|
+
Consumer->>Op: Boleta.generar(...) construye
|
|
32
|
+
Consumer->>Op: call(id_comercio, sid)
|
|
33
|
+
Op->>Cli: Client.new(id, sid, http_method)
|
|
34
|
+
Op->>Cli: call(request)
|
|
35
|
+
Cli->>Cli: comercio.merge(request) agrega handshake MD5
|
|
36
|
+
alt client_to_use soap (default)
|
|
37
|
+
Cli->>WS: webservice_cobrodigital via savon
|
|
38
|
+
else client_to_use https
|
|
39
|
+
Cli->>WS: Net HTTP Post o Get
|
|
40
|
+
end
|
|
41
|
+
WS-->>Cli: respuesta cruda
|
|
42
|
+
Cli-->>Op: guarda en response
|
|
43
|
+
Consumer->>Op: parse_response
|
|
44
|
+
Op-->>Consumer: resultado, log, datos
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Contexto:** `parse_response` decodifica el JSON de `output`, evalúa `ejecucion_correcta == '1'` y aplana `datos`. No levanta excepción ante `resultado: false` (`lib/cobro_digital/operador.rb:22`).
|
|
48
|
+
|
|
49
|
+
### 2.2 Batch meta
|
|
50
|
+
|
|
51
|
+
`Meta.meta` toma una lista de operaciones ya construidas y las indexa en un único payload. Cada sub-operación conserva su `metodo_webservice`. Se ejecuta como una sola llamada POST.
|
|
52
|
+
|
|
53
|
+
```mermaid
|
|
54
|
+
sequenceDiagram
|
|
55
|
+
actor Consumer
|
|
56
|
+
participant Meta as Meta
|
|
57
|
+
participant Cli as Client
|
|
58
|
+
participant WS as WS CobroDigital
|
|
59
|
+
|
|
60
|
+
Consumer->>Meta: meta([op0, op1, ...]) construye
|
|
61
|
+
Meta->>Meta: render(objs) indexa 0 => op0.render, 1 => op1.render
|
|
62
|
+
Consumer->>Meta: call(id_comercio, sid)
|
|
63
|
+
Meta->>Cli: call(request) metodo_webservice meta
|
|
64
|
+
Cli->>WS: POST batch
|
|
65
|
+
WS-->>Cli: respuesta cruda
|
|
66
|
+
Cli-->>Meta: guarda en response
|
|
67
|
+
Consumer->>Meta: parse_response
|
|
68
|
+
Meta-->>Consumer: resultado, log, datos
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Contexto:** `Meta.transaction` es un helper que pre-arma una `Transaccion.consultar` con filtro tipo=ingreso por default (`lib/cobro_digital/meta.rb:42`).
|
|
72
|
+
|
|
73
|
+
## 3. Inferencias
|
|
74
|
+
|
|
75
|
+
| inferencia | confidence | a verificar |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| el batch `meta` se procesa server-side como unidad (atomicidad) | unknown | el código no lo expresa; preguntar a CobroDigital |
|
|
78
|
+
| la selección GET vs POST por operación es exigida por el WS | inferred | cada constructor fija `http_method`; confirmar que el WS lo requiere así |
|
|
79
|
+
|
|
80
|
+
## 4. Cobertura y fronteras
|
|
81
|
+
|
|
82
|
+
- **Cobertura:** 2 flujos, los dos caminos de ejecución reales de la gema.
|
|
83
|
+
- **No documentado:** el procesamiento interno del WS (caja negra del proveedor); el manejo de reintentos/timeout en degradación → `docs/consumed §c/§e`.
|
|
84
|
+
- **Mermaid:** diagramas pasados por el checklist render-safe (sin `;`, sin `::` en mensajes, un solo `:` por mensaje, ids no reservados).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Configuración — cobro_digital
|
|
2
|
+
|
|
3
|
+
> meta: artefacto · RFC-012 · generado arch-structure + arch-enrich · anclado a v1.9.0 · inventario base + §f cobertura 2/2
|
|
4
|
+
|
|
5
|
+
## 1. Resumen
|
|
6
|
+
|
|
7
|
+
Gema con configuración mínima: dos variables de entorno (`ENDPOINT_COBRODIGITAL` selecciona el endpoint del WS; `COBRODIGITAL_LOG_LEVEL` el nivel de log del cliente SOAP), más constantes de tuning fijas en código (`TIMEOUT`, cliente default, filtros de log). Las credenciales del comercio (`id_comercio`, `sid`) NO son configuración de entorno: se pasan por argumento en cada `#call`.
|
|
8
|
+
|
|
9
|
+
## 2. §a Hecho verificable
|
|
10
|
+
|
|
11
|
+
| métrica | valor |
|
|
12
|
+
|---|---|
|
|
13
|
+
| total vars (env) | 2 |
|
|
14
|
+
| requeridas | 0 |
|
|
15
|
+
| con default | 2 |
|
|
16
|
+
| derivadas | 3 (`URI`, `WSDL` ← `ENDPOINT_COBRODIGITAL`; `LOG_LEVEL` ← `COBRODIGITAL_LOG_LEVEL`) |
|
|
17
|
+
| secretas (env) | 0 |
|
|
18
|
+
|
|
19
|
+
## 3. §b Inventario base
|
|
20
|
+
|
|
21
|
+
| nombre | tipo | requerida | default | origen | consumidor (file:line) | secret? | categoría | failure-mode | side-effect | business reason |
|
|
22
|
+
|---|---|---|---|---|---|---|---|---|---|---|
|
|
23
|
+
| `ENDPOINT_COBRODIGITAL` | String (URL base) | no | `https://cobro.digital:14365` | env | `lib/cobro_digital.rb:21-22` | no | — | — | — | — |
|
|
24
|
+
| `COBRODIGITAL_LOG_LEVEL` | Symbol (nivel de log) | no | `error` | env | `lib/cobro_digital.rb:30-31` | no | — | — | — | — |
|
|
25
|
+
|
|
26
|
+
**Constantes de runtime (no env, fijas en código — `lib/cobro_digital.rb`):**
|
|
27
|
+
|
|
28
|
+
| constante | valor | nota |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `CobroDigital::TIMEOUT` | `300` | open/read timeout (s) para SOAP y HTTPS |
|
|
31
|
+
| `CobroDigital::SOAP` | `'soap'` | cliente default si no se pasa `:con_client` |
|
|
32
|
+
| `CobroDigital::URI` | `"#{endpoint}/ws3/"` | derivada — ver §d |
|
|
33
|
+
| `CobroDigital::WSDL` | `"#{endpoint}/ws3/?wsdl"` | derivada — ver §d |
|
|
34
|
+
| `CobroDigital::LOG_LEVEL` | `error` (default) | derivada de `COBRODIGITAL_LOG_LEVEL` (string vacío → `error`) |
|
|
35
|
+
| `CobroDigital::DEBUG_LOG` | `false` (default) | `true` solo si `LOG_LEVEL == :debug`; gobierna `pretty_print_xml` |
|
|
36
|
+
| `CobroDigital::LOG_FILTERS` | `[:parametros_de_entrada]` | nodo SOAP enmascarado (`***FILTERED***`) — protege sid + PII |
|
|
37
|
+
|
|
38
|
+
**Credenciales (NO configuración de entorno — argumentos de invocación):**
|
|
39
|
+
|
|
40
|
+
| dato | dónde entra | secret? |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `id_comercio` | argumento de `Operador#call(id_comercio, sid, …)` / `Client.new(id_comercio:)` | no |
|
|
43
|
+
| `sid` | argumento de `Operador#call(id_comercio, sid, …)` / `Client.new(sid:)` | **sí** |
|
|
44
|
+
|
|
45
|
+
## 4. §d Derivaciones simples
|
|
46
|
+
|
|
47
|
+
| var derivada | fórmula |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `CobroDigital::URI` | `(ENV['ENDPOINT_COBRODIGITAL'] \|\| 'https://cobro.digital:14365') + '/ws3/'` |
|
|
50
|
+
| `CobroDigital::WSDL` | `(ENV['ENDPOINT_COBRODIGITAL'] \|\| 'https://cobro.digital:14365') + '/ws3/?wsdl'` |
|
|
51
|
+
| `CobroDigital::LOG_LEVEL` | `_l = ENV['COBRODIGITAL_LOG_LEVEL'].to_s; (_l.empty? ? 'error' : _l).to_sym` |
|
|
52
|
+
|
|
53
|
+
> Todas se evalúan **una vez al cargar la gema** (`require`). Cambiar las env en runtime tras el `require` NO re-deriva las constantes.
|
|
54
|
+
|
|
55
|
+
## 5. §c/§e/§i/§j (sembrados)
|
|
56
|
+
|
|
57
|
+
- **§e Scheduling:** no aplica (gema sin scheduler).
|
|
58
|
+
- **§i Inyecciones al host:** no aplica (no hay Railtie/Engine; la gema no muta el host).
|
|
59
|
+
- **§j Inyección a gemas configuradas:** no aplica (no hay bloque `configure`; el `@with_handshake` configurable está comentado en `Client#initialize`).
|
|
60
|
+
- Campos `categoría · failure-mode · side-effect · scope-override · business reason` de §b: `—` (los llena `arch-enrich`).
|
|
61
|
+
|
|
62
|
+
## f. Enriquecimiento semántico
|
|
63
|
+
|
|
64
|
+
> cobertura: 2/2 vars enriquecidas; ausencia ≠ "no aplica".
|
|
65
|
+
|
|
66
|
+
### f.1 endpoint (`ENDPOINT_COBRODIGITAL`)
|
|
67
|
+
|
|
68
|
+
| var | categoría | failure-mode | side-effect | scope-override | business-reason / definición |
|
|
69
|
+
|---|---|---|---|---|---|
|
|
70
|
+
| `ENDPOINT_COBRODIGITAL` | integration | `silent-default` @ require — si falta, usa producción (`https://cobro.digital:14365`) silenciosamente | `restart` (las constantes `URI`/`WSDL` se `freeze`an al cargar la gema) | `boot-only` | selecciona el entorno del WS de CobroDigital (sandbox vs producción). **Sin var ⇒ producción.** Un entorno de pruebas que olvide setearla pega contra el WS real → riesgo de crear pagadores/boletas reales. |
|
|
71
|
+
|
|
72
|
+
### f.2 logging (`COBRODIGITAL_LOG_LEVEL`)
|
|
73
|
+
|
|
74
|
+
| var | categoría | failure-mode | side-effect | scope-override | business-reason / definición |
|
|
75
|
+
|---|---|---|---|---|---|
|
|
76
|
+
| `COBRODIGITAL_LOG_LEVEL` | observability | `silent-default` @ require — sin var ⇒ `:error` (no loguea el body del request) | `restart` (constante evaluada al cargar la gema) | `boot-only` | controla la verbosidad del log de Savon. **Seguridad:** con `=debug` el XML formateado expone el `sid` + PII del pagador en claro → no habilitar en producción. El nodo `parametros_de_entrada` se enmascara vía `LOG_FILTERS` aun en debug, pero `pretty_print_xml` sigue exponiendo el body. |
|
|
77
|
+
|
|
78
|
+
**Ramificadores:** ninguno (no condiciona otras vars).
|
|
79
|
+
|
|
80
|
+
**Threading:** n/a (constantes evaluadas una vez al `require`).
|
|
81
|
+
|
|
82
|
+
## 6. Cobertura y fronteras
|
|
83
|
+
|
|
84
|
+
- **Cobertura:** total. Una sola env var; resto es tuning fijo en código.
|
|
85
|
+
- **Heurística a verificar (humano):** `ENDPOINT_COBRODIGITAL` se infiere `requerida=no` por tener default literal embebido. Confirmar que apuntar a producción vs sandbox se hace solo cambiando esta var.
|
|
86
|
+
- **Sin valor real comprometido:** el inventario no incluye literales de credenciales (las credenciales no son env vars).
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Dependencias consumidas — cobro_digital → WS CobroDigital
|
|
2
|
+
|
|
3
|
+
> meta: artefacto · RFC-018 · generado arch-structure + arch-enrich · anclado a v1.9.0 · cobertura estructural (§a/§b/§d) + §c/§e enriquecidos 2/2
|
|
4
|
+
|
|
5
|
+
## 1. Resumen
|
|
6
|
+
|
|
7
|
+
La gema **es** un adaptador: su única dependencia consumida es el Web Service v3 de CobroDigital (pasarela de pago externa). Toda la superficie pública de la gema termina en una llamada a un único método SOAP (`webservice_cobrodigital`) o a su equivalente HTTPS sobre `…/ws3/`.
|
|
8
|
+
|
|
9
|
+
## 2. §a Identidad
|
|
10
|
+
|
|
11
|
+
| campo | valor |
|
|
12
|
+
|---|---|
|
|
13
|
+
| proveedor/servicio | CobroDigital — WS v3 (pasarela de pago) |
|
|
14
|
+
| sub-tipo | **externo** (no es repo del fleet) |
|
|
15
|
+
| transporte | SOAP 1.x sobre HTTPS (default) · HTTP form POST/GET (alternativo) |
|
|
16
|
+
| cliente nuestro | `CobroDigital::Client` (`lib/cobro_digital.rb`); SOAP vía `savon ~> 2.12.1`, HTTPS vía `Net::HTTP` |
|
|
17
|
+
| endpoint | `https://cobro.digital:14365/ws3/` (default); override por `ENV['ENDPOINT_COBRODIGITAL']` |
|
|
18
|
+
| WSDL | `…/ws3/?wsdl` |
|
|
19
|
+
| auth | credenciales de comercio en cada request: `idComercio` + `sid` + `handshake` (MD5 de `Time.now.to_f`) — ver `Client#comercio` |
|
|
20
|
+
| doc oficial | Manual de implementación entregado por CobroDigital (no versionado en el repo); <http://cobrodigital.com> |
|
|
21
|
+
|
|
22
|
+
## 3. §b Operaciones consumidas
|
|
23
|
+
|
|
24
|
+
Todas viajan como un único método SOAP `webservice_cobrodigital` cuyo `parametros_de_entrada` es el JSON de `comercio.merge(request)`. El campo `metodo_webservice` discrimina la operación real:
|
|
25
|
+
|
|
26
|
+
| operación (`metodo_webservice`) | transporte | qué mandamos | constructor de la gema |
|
|
27
|
+
|---|---|---|---|
|
|
28
|
+
| `crear_pagador` | POST | `{ pagador: {…} }` | `Pagador.crear` |
|
|
29
|
+
| `editar_pagador` | POST | `{ identificador, buscar, pagador }` | `Pagador.editar` |
|
|
30
|
+
| `verificar_existencia_pagador` | GET | `{ identificador, buscar }` | `Pagador.verificar` |
|
|
31
|
+
| `obtener_codigo_electronico` | GET | `{ identificador, buscar }` | `Pagador.codigo_electronico` |
|
|
32
|
+
| `consultar_estructura_pagadores` | GET | `{}` | `Pagador.estructura_de_datos` |
|
|
33
|
+
| `generar_boleta` | POST | `{ identificador, buscar, fechas_vencimiento[`%Y%m%d`], importes, concepto, plantilla }` | `Boleta.generar` |
|
|
34
|
+
| `inhabilitar_boleta` | POST | `{ nro_boleta }` | `Boleta.inhabilitar` |
|
|
35
|
+
| `obtener_codigo_de_barras` | GET | `{ nro_boleta }` | `Boleta.obtener_codigo_de_barras` |
|
|
36
|
+
| `consultar_transacciones` | GET | `{ desde[`%Y%m%d`], hasta[`%Y%m%d`], filtros }` | `Transaccion.consultar` |
|
|
37
|
+
| `consultar_actividad_micrositio` | GET | `{ identificador, buscar, desde, hasta }` | `Micrositio.consultar_actividad` |
|
|
38
|
+
| `meta` | POST | `{ 0 => {metodo_webservice,…}, 1 => {…}, … }` (batch) | `Meta.meta` |
|
|
39
|
+
|
|
40
|
+
**Respuesta (forma común):** el WS responde un sobre cuyo `output` es un JSON string. `Operador#parse_response` lo decodifica a:
|
|
41
|
+
|
|
42
|
+
| clave | origen en el JSON del WS | tipo |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `resultado` | `ejecucion_correcta == '1'` | Boolean |
|
|
45
|
+
| `log` | `log` | Array\<String\> (mensajes / errores) |
|
|
46
|
+
| `datos` | `datos` (opcional) | Array (aplanado; cada fila se intenta `JSON.parse`) |
|
|
47
|
+
|
|
48
|
+
## 4. §d Errores del proveedor → mapeo nuestro
|
|
49
|
+
|
|
50
|
+
| condición del proveedor | manejo en la gema | excepción nuestra |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `ejecucion_correcta != '1'` | `parse_response` devuelve `resultado: false` + `log` con los mensajes; **no levanta excepción** | — (no se traduce a excepción; el consumidor inspecciona `resultado`/`log`) |
|
|
53
|
+
| fallo de transporte SOAP (HTTP ≠ 200, SOAP Fault) | sin `rescue` en la gema → propaga | `Savon::SOAPFault` / `Savon::HTTPError` (de `savon`, sin envolver) |
|
|
54
|
+
| fallo de transporte HTTPS | sin `rescue` en la gema → propaga | excepción de `Net::HTTP` (sin envolver) |
|
|
55
|
+
| `output` no parseable como JSON | sin `rescue` en `parse_response` (el `rescue` interno solo cubre filas de `datos`) | `JSON::ParserError` (sin envolver) |
|
|
56
|
+
|
|
57
|
+
> La gema **no define excepciones propias** ni mapea las del proveedor a un catálogo propio → por eso `docs/errors/` es `n/a` para este repo (ver Mapa de conocimiento en `AGENTS.md`).
|
|
58
|
+
|
|
59
|
+
## 5. §c Semántica de retry/idempotencia
|
|
60
|
+
|
|
61
|
+
| aspecto | estado | detalle |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| retry | **no implementado** | la gema no reintenta; `TIMEOUT = 300s` open/read (`lib/cobro_digital.rb:20`). Cualquier reintento es responsabilidad del consumidor. |
|
|
64
|
+
| idempotencia de escrituras | **no garantizada por el WS** | `crear_pagador` es **no idempotente**: el WS no deduplica (README §Crear Pagador: "es posible dar de alta eternamente el mismo pagador"). Reintentar a ciegas un POST puede duplicar pagadores/boletas. |
|
|
65
|
+
| seguridad del reintento | condicional | **lecturas** (GET: `verificar`, `consultar_*`, `obtener_*`) son seguras de reintentar. **escrituras** (POST: `crear/editar_pagador`, `generar/inhabilitar_boleta`, `meta`) NO — verificar estado antes de reintentar. |
|
|
66
|
+
| rol del `handshake` | `unknown` | se regenera por request (`Client#comercio`); no se confirmó si el WS lo usa como clave de idempotencia/anti-replay → no asumir que dedup. Verificar con el manual de CobroDigital. |
|
|
67
|
+
|
|
68
|
+
## 6. §e Degradación (qué pasa si CobroDigital cae)
|
|
69
|
+
|
|
70
|
+
| escenario | comportamiento actual | decisión de negocio |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| WS no responde / timeout (300s) | la excepción de transporte (`Savon::*` / `Net::HTTP`) **propaga sin envolver** al consumidor | no hay fallback ni cola en la gema; el consumidor decide reintento/cola/degradación |
|
|
73
|
+
| WS responde error de negocio (`ejecucion_correcta != '1'`) | `parse_response` devuelve `resultado: false` + `log`; **no excepción** | el consumidor debe inspeccionar `resultado` y actuar; un flujo que ignore `resultado` trata un fallo como éxito |
|
|
74
|
+
| SLA del proveedor | `unknown` | no documentado en el repo; consultar contrato con CobroDigital |
|
|
75
|
+
|
|
76
|
+
> **Sin fallback local:** la gema es un transporte fino. Toda resiliencia (retry con backoff, circuit-breaker, cola de outbox para escrituras) vive —o debería— en el host consumidor, no acá.
|
|
77
|
+
|
|
78
|
+
## 7. Cobertura y fronteras
|
|
79
|
+
|
|
80
|
+
- **Cobertura:** §a/§b/§d estructurales + §c/§e enriquecidos, anclados al código del cliente.
|
|
81
|
+
- **Subset, no la API completa:** se documentan solo los 11 métodos que la gema expone vía constructores; el WS de CobroDigital puede ofrecer más.
|
|
82
|
+
- **Fuera de alcance:** el wire-schema interno de cada payload del WS (campos opcionales, validaciones server-side) vive en el Manual de implementación de CobroDigital, no versionado acá.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Glosario — cobro_digital
|
|
2
|
+
|
|
3
|
+
> meta: artefacto · RFC-009 · generado arch-enrich · anclado a v1.9.0 · cobertura parcial (acreta por PR); ausencia ≠ inexistencia
|
|
4
|
+
|
|
5
|
+
## 1. Resumen
|
|
6
|
+
|
|
7
|
+
Lenguaje ubicuo del bounded context de la gema: los términos del dominio de cobranza de CobroDigital tal como los modela esta gema. Sin capa de datos propia (`docs/data/` = n/a), el `**Binding:**` apunta al símbolo público que materializa el concepto (`docs/interface/interface.md`), no a tabla/columna.
|
|
8
|
+
|
|
9
|
+
## 2. Términos
|
|
10
|
+
|
|
11
|
+
## comercio
|
|
12
|
+
|
|
13
|
+
La entidad cliente de CobroDigital que usa el webservice. Se identifica en cada request con dos credenciales emitidas por CobroDigital al dar de alta: `id_comercio` (identificador público) y `sid` (secreto). No es un objeto del dominio de la gema — son argumentos de `#call` que viajan en el bloque de identificación.
|
|
14
|
+
|
|
15
|
+
**Binding:** `CobroDigital::Client#id_comercio`, `CobroDigital::Client#sid`; bloque armado en `Client#comercio` (`lib/cobro_digital.rb:84`).
|
|
16
|
+
|
|
17
|
+
## handshake
|
|
18
|
+
|
|
19
|
+
Token anti-replay que acompaña la identificación del comercio en cada request: el MD5 de `Time.now.to_f`. Se regenera por llamada. El comentario `@with_handshake` (comentado en `Client#initialize`) sugiere que alguna vez fue opcional; hoy es siempre-on.
|
|
20
|
+
|
|
21
|
+
**Binding:** `Client#comercio` → `Digest::MD5.hexdigest(Time.now.to_f.to_s)` (`lib/cobro_digital.rb:85`).
|
|
22
|
+
|
|
23
|
+
## pagador
|
|
24
|
+
|
|
25
|
+
El cliente final al que el comercio le factura (a quien se le cobra). Su forma (campos) la define cada comercio con CobroDigital — la gema no la valida ni la fija. El WS **no controla duplicados**: dar de alta el mismo pagador dos veces crea dos. El control de unicidad es del consumidor.
|
|
26
|
+
|
|
27
|
+
**Binding:** `CobroDigital::Pagador` (`lib/cobro_digital/pagador.rb`).
|
|
28
|
+
|
|
29
|
+
## identificador / buscar
|
|
30
|
+
|
|
31
|
+
Par clave-valor para localizar un pagador en el WS: `identificador` es el nombre del campo identificador (ej. `'Su_identificador'`, `'id'`); `buscar` es el valor a matchear (ej. `1234`). Aparece en casi toda operación que opera sobre un pagador existente.
|
|
32
|
+
|
|
33
|
+
**Binding:** argumentos de `Pagador.editar/verificar/codigo_electronico`, `Boleta.generar`, `Micrositio.consultar_actividad`.
|
|
34
|
+
|
|
35
|
+
## boleta
|
|
36
|
+
|
|
37
|
+
El documento de cobro que el comercio informa a CobroDigital para que ejecute el cobro por los medios de la pasarela. Lleva hasta 4 vencimientos (el 1º = fecha de emisión) y hasta 4 importes (el 1º = valor; el resto = recargos por vencimiento). Generarla devuelve un número de boleta.
|
|
38
|
+
|
|
39
|
+
**Binding:** `CobroDigital::Boleta` (`lib/cobro_digital/boleta.rb`).
|
|
40
|
+
|
|
41
|
+
## codigo electronico
|
|
42
|
+
|
|
43
|
+
Código que habilita a los pagadores a pagar por PagosMisCuentas y LinkPagos. Solo se puede obtener **después** de generada la primera boleta del pagador.
|
|
44
|
+
|
|
45
|
+
**Binding:** `Pagador.codigo_electronico` → WS `obtener_codigo_electronico` (`lib/cobro_digital/pagador.rb:34`).
|
|
46
|
+
|
|
47
|
+
## codigo de barras
|
|
48
|
+
|
|
49
|
+
String del código de barras de una boleta (uno por vencimiento/importe). Para renderizarlo a imagen se usa el código 128b (la gema no renderiza; sugiere `barby`).
|
|
50
|
+
|
|
51
|
+
**Binding:** `Boleta.obtener_codigo_de_barras` → WS `obtener_codigo_de_barras`.
|
|
52
|
+
|
|
53
|
+
## plantilla
|
|
54
|
+
|
|
55
|
+
Modelo de estilo/formato de la boleta. Cada comercio la provee/acuerda con CobroDigital (ej. `'init_273'`). Argumento opcional de `Boleta.generar`.
|
|
56
|
+
|
|
57
|
+
**Binding:** parámetro `plantilla` de `Boleta.generar` (`lib/cobro_digital/boleta.rb:9`).
|
|
58
|
+
|
|
59
|
+
## transaccion
|
|
60
|
+
|
|
61
|
+
Un movimiento de la cuenta del comercio en CobroDigital. Se consulta por rango de fechas con filtros. Tipos:
|
|
62
|
+
|
|
63
|
+
- **ingreso** (`ingresos`): todo lo que incrementa el saldo de la cuenta; generalmente las cobranzas.
|
|
64
|
+
- **egreso** (`egresos`): retiros del dinero depositado por los pagadores.
|
|
65
|
+
- **tarjeta_credito**: cobranzas abonadas con tarjeta de crédito.
|
|
66
|
+
- **debito_automatico**: débitos realizados por CBU.
|
|
67
|
+
|
|
68
|
+
**Binding:** `CobroDigital::Transaccion` + constantes `FILTRO_TIPO_*` (`lib/cobro_digital/transaccion.rb`).
|
|
69
|
+
|
|
70
|
+
## micrositio
|
|
71
|
+
|
|
72
|
+
El sitio de pago que CobroDigital expone para un pagador. La gema consulta su **actividad** en un rango de fechas.
|
|
73
|
+
|
|
74
|
+
**Binding:** `CobroDigital::Micrositio.consultar_actividad` → WS `consultar_actividad_micrositio`.
|
|
75
|
+
|
|
76
|
+
## meta
|
|
77
|
+
|
|
78
|
+
Operación batch: agrupa N operaciones (crear pagadores, generar/inhabilitar boletas, etc.) en una sola llamada al WS, indexadas `{ 0 => …, 1 => … }`. Cada sub-operación lleva su propio `metodo_webservice` y `handshake`.
|
|
79
|
+
|
|
80
|
+
**Binding:** `CobroDigital::Meta.meta(objs)` → WS `meta` (`lib/cobro_digital/meta.rb:64`).
|
|
81
|
+
|
|
82
|
+
## resultado / log / datos
|
|
83
|
+
|
|
84
|
+
La tripleta de la respuesta parseada (`Operador#parse_response`): `resultado` (Boolean, éxito de la consulta), `log` (mensajes/errores del WS), `datos` (payload de la consulta, opcional). Es el contrato de salida que todo consumidor inspecciona.
|
|
85
|
+
|
|
86
|
+
**Binding:** `Operador#parse_response` (`lib/cobro_digital/operador.rb:22`).
|
|
87
|
+
|
|
88
|
+
## 3. Inferencias
|
|
89
|
+
|
|
90
|
+
| término | inferencia | confidence | a verificar |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| handshake | propósito anti-replay/idempotencia | inferred | confirmar con manual de CobroDigital si el WS lo valida o lo ignora |
|
|
93
|
+
| meta | el batch es transaccional (todo-o-nada) o best-effort | unknown | preguntar a CobroDigital — el código no lo expresa |
|
|
94
|
+
| micrositio | "actividad" = pagos/visitas/intentos | inferred | precisar qué devuelve `datos` para esta consulta |
|
|
95
|
+
|
|
96
|
+
## 4. Cobertura y fronteras
|
|
97
|
+
|
|
98
|
+
- **Cobertura:** parcial declarada. Cubre los términos materializados en la superficie pública actual. Acreta por PR que toque el dominio.
|
|
99
|
+
- **Sin binding tabular:** gema sin DB; los bindings apuntan a símbolos públicos (ISO 11179 admite materialización no-tabular cuando hay símbolo estable que *es* el concepto).
|
|
100
|
+
- **Candidatos a glosario canónico (RFC-019):** `boleta`, `pagador`, `transaccion` probablemente aparecen en otros repos del fleet que integran cobranza → **flaggeados** como candidatos a entrada canónica. arch-enrich no la crea (es cross-repo); se propone la promoción.
|
|
101
|
+
- **No documentado:** la semántica fina de los campos del payload del WS (los define el manual de CobroDigital, no versionado acá).
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Interfaz — cobro_digital
|
|
2
|
+
|
|
3
|
+
> meta: artefacto · RFC-004 · generado arch-structure · anclado a v1.9.0 · cobertura total de `lib/**`
|
|
4
|
+
|
|
5
|
+
## 1. Resumen
|
|
6
|
+
|
|
7
|
+
API Ruby pública de la gema adaptadora del WS de CobroDigital. Superficie: el módulo `CobroDigital` con el transporte `Client`, la clase base `Operador` y cinco subclases-operación (`Pagador`, `Boleta`, `Transaccion`, `Micrositio`, `Meta`) que se construyen con métodos de clase y se ejecutan con `#call`.
|
|
8
|
+
|
|
9
|
+
## 2. Símbolos públicos
|
|
10
|
+
|
|
11
|
+
| símbolo | tipo | nota |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `CobroDigital` | módulo | namespace raíz (`lib/cobro_digital.rb`) |
|
|
14
|
+
| `CobroDigital::SOAP` | constante (`'soap'`) | cliente de transporte default |
|
|
15
|
+
| `CobroDigital::HTTPS` | constante (`'https'`) | cliente de transporte alternativo |
|
|
16
|
+
| `CobroDigital::CLIENTS` | constante (`[SOAP, HTTPS]`) | clientes soportados |
|
|
17
|
+
| `CobroDigital::URI` | constante (String) | endpoint `…/ws3/`; derivada de `ENV['ENDPOINT_COBRODIGITAL']` |
|
|
18
|
+
| `CobroDigital::WSDL` | constante (String) | endpoint `…/ws3/?wsdl`; derivada de `ENV['ENDPOINT_COBRODIGITAL']` |
|
|
19
|
+
| `CobroDigital::TIMEOUT` | constante (`300`) | open/read timeout en segundos |
|
|
20
|
+
| `CobroDigital::LOG_LEVEL` | constante (Symbol) | nivel de log del cliente SOAP; derivada de `ENV['COBRODIGITAL_LOG_LEVEL']` (default `:error`) |
|
|
21
|
+
| `CobroDigital::DEBUG_LOG` | constante (Boolean) | `true` si `LOG_LEVEL == :debug`; gobierna `pretty_print_xml` |
|
|
22
|
+
| `CobroDigital::LOG_FILTERS` | constante (`[:parametros_de_entrada]`) | nodo SOAP enmascarado en el log (protege sid + PII) |
|
|
23
|
+
| `CobroDigital::Https` | módulo | namespace de métodos HTTP |
|
|
24
|
+
| `CobroDigital::Https::POST` | constante (`'Post'`) | método HTTP POST |
|
|
25
|
+
| `CobroDigital::Https::GET` | constante (`'Get'`) | método HTTP GET |
|
|
26
|
+
| `CobroDigital::Client` | clase | transporte hacia el WS |
|
|
27
|
+
| `CobroDigital::Client#id_comercio` | attr_accessor | credencial del comercio |
|
|
28
|
+
| `CobroDigital::Client#sid` | attr_accessor | credencial del comercio (secreto) |
|
|
29
|
+
| `CobroDigital::Client#client_to_use` | attr_accessor | `'soap'` \| `'https'` |
|
|
30
|
+
| `CobroDigital::Client#http_method` | attr_accessor | `'Post'` \| `'Get'` (solo transporte HTTPS) |
|
|
31
|
+
| `CobroDigital::Client#pagadores` | attr_accessor | acumulador (Array, inicializa `[]`) |
|
|
32
|
+
| `CobroDigital::Client#boletas` | attr_accessor | acumulador (Array, inicializa `[]`) |
|
|
33
|
+
| `CobroDigital::Client#transacciones` | attr_accessor | acumulador (Array, inicializa `[]`) |
|
|
34
|
+
| `CobroDigital::Client#micrositios` | attr_accessor | acumulador (Array, inicializa `[]`) |
|
|
35
|
+
| `CobroDigital::Client#requests` | attr_accessor | sin inicializar en `#initialize` |
|
|
36
|
+
| `CobroDigital::Client#request_xml` | attr_accessor | XML del último request SOAP (`#soap_client`) |
|
|
37
|
+
| `CobroDigital::Client#initialize(attrs={})` | método de instancia | `attrs`: `:id_comercio`, `:sid`, `:con_client`, `:http_method`; levanta `ArgumentError` si `client_to_use` ∉ `CLIENTS` |
|
|
38
|
+
| `CobroDigital::Client#soap_client(params)` | método de instancia | arma y ejecuta el request Savon `:webservice_cobrodigital` |
|
|
39
|
+
| `CobroDigital::Client#https_client(params)` | método de instancia | ejecuta vía `Net::HTTP` (`Post`/`Get`) |
|
|
40
|
+
| `CobroDigital::Client#call(request)` | método de instancia | despacha a `#{client_to_use}_client` mergeando `#comercio` |
|
|
41
|
+
| `CobroDigital::Client#comercio` | método de instancia | bloque de identificación `{idComercio, sid, handshake}` (handshake = MD5) |
|
|
42
|
+
| `CobroDigital::Operador` | clase | clase base de las operaciones |
|
|
43
|
+
| `CobroDigital::Operador#http_method` | attr_accessor | método HTTP del transporte |
|
|
44
|
+
| `CobroDigital::Operador#webservice` | attr_accessor | nombre del método del WS |
|
|
45
|
+
| `CobroDigital::Operador#render` | attr_accessor | payload de la operación (Hash) |
|
|
46
|
+
| `CobroDigital::Operador#response` | attr_accessor | respuesta cruda tras `#call` |
|
|
47
|
+
| `CobroDigital::Operador#client` | attr_accessor | `Client` instanciado en `#call` |
|
|
48
|
+
| `CobroDigital::Operador#initialize(attrs={})` | método de instancia | `attrs`: `:http_method`, `:webservice`, `:render` |
|
|
49
|
+
| `CobroDigital::Operador#request` | método de instancia | `{ metodo_webservice: webservice }.merge(render)` |
|
|
50
|
+
| `CobroDigital::Operador#call(id_comercio, sid, opt={})` | método de instancia | instancia `Client` y ejecuta; guarda `#response` |
|
|
51
|
+
| `CobroDigital::Operador#parse_response` | método de instancia | decodifica el JSON de salida → `{ resultado:, log:, datos: }` |
|
|
52
|
+
| `CobroDigital::Pagador` | clase `< Operador` | operaciones sobre pagadores |
|
|
53
|
+
| `CobroDigital::Pagador::CREAR_PAGADOR_WS` | constante (`'crear_pagador'`) | nombre del método WS |
|
|
54
|
+
| `CobroDigital::Pagador::EDITAR_PAGADOR_WS` | constante (`'editar_pagador'`) | nombre del método WS |
|
|
55
|
+
| `CobroDigital::Pagador::VERIFICAR_PAGADOR_WS` | constante (`'verificar_existencia_pagador'`) | nombre del método WS |
|
|
56
|
+
| `CobroDigital::Pagador::OBTENER_CODIGO_ELECTRONICO_WS` | constante (`'obtener_codigo_electronico'`) | nombre del método WS |
|
|
57
|
+
| `CobroDigital::Pagador::CONSULTAR_ESTRUCTURA_PAGADORES_WS` | constante (`'consultar_estructura_pagadores'`) | nombre del método WS |
|
|
58
|
+
| `CobroDigital::Pagador.crear(pagador)` | método de clase (constructor) | POST; `render: { pagador: }` |
|
|
59
|
+
| `CobroDigital::Pagador.editar(identificador, buscar, pagador)` | método de clase (constructor) | POST |
|
|
60
|
+
| `CobroDigital::Pagador.verificar(identificador, buscar)` | método de clase (constructor) | GET |
|
|
61
|
+
| `CobroDigital::Pagador.codigo_electronico(identificador, buscar)` | método de clase (constructor) | GET |
|
|
62
|
+
| `CobroDigital::Pagador.estructura_de_datos` | método de clase (constructor) | GET; `render: {}` |
|
|
63
|
+
| `CobroDigital::Boleta` | clase `< Operador` | operaciones sobre boletas |
|
|
64
|
+
| `CobroDigital::Boleta::GENERAR_BOLETA_WS` | constante (`'generar_boleta'`) | nombre del método WS |
|
|
65
|
+
| `CobroDigital::Boleta::INHABILITAR_BOLETA_WS` | constante (`'inhabilitar_boleta'`) | nombre del método WS |
|
|
66
|
+
| `CobroDigital::Boleta::OBTENER_CODIGO_BARRA_WS` | constante (`'obtener_codigo_de_barras'`) | nombre del método WS |
|
|
67
|
+
| `CobroDigital::Boleta.generar(identificador, buscar, fechas_vencimiento, importes, concepto, plantilla=nil)` | método de clase (constructor) | POST; `fechas_vencimiento` se formatean a `%Y%m%d` |
|
|
68
|
+
| `CobroDigital::Boleta.inhabilitar(nro_boleta)` | método de clase (constructor) | POST |
|
|
69
|
+
| `CobroDigital::Boleta.obtener_codigo_de_barras(nro_boleta)` | método de clase (constructor) | GET |
|
|
70
|
+
| `CobroDigital::Transaccion` | clase `< Operador` | consulta de transacciones |
|
|
71
|
+
| `CobroDigital::Transaccion::CONSULTAR_TRANSACCIONES_WS` | constante (`'consultar_transacciones'`) | nombre del método WS |
|
|
72
|
+
| `CobroDigital::Transaccion::FILTRO_TIPO` | constante (`'tipo'`) | clave de filtro |
|
|
73
|
+
| `CobroDigital::Transaccion::FILTRO_NOMBRE` | constante (`'nombre'`) | clave de filtro |
|
|
74
|
+
| `CobroDigital::Transaccion::FILTRO_CONCEPTO` | constante (`'concepto'`) | clave de filtro |
|
|
75
|
+
| `CobroDigital::Transaccion::FILTRO_NRO_BOLETA` | constante (`'nro_boleta'`) | clave de filtro |
|
|
76
|
+
| `CobroDigital::Transaccion::FILTRO_IDENTIFICADOR` | constante (`'identificador'`) | clave de filtro |
|
|
77
|
+
| `CobroDigital::Transaccion::FILTRO_TIPO_EGRESO` | constante (`'egresos'`) | valor de filtro tipo |
|
|
78
|
+
| `CobroDigital::Transaccion::FILTRO_TIPO_INGRESO` | constante (`'ingresos'`) | valor de filtro tipo |
|
|
79
|
+
| `CobroDigital::Transaccion::FILTRO_TIPO_TARJETA_CREDITO` | constante (`'tarjeta_credito'`) | valor de filtro tipo |
|
|
80
|
+
| `CobroDigital::Transaccion::FILTRO_TIPO_DEBITO_AUTOMATICO` | constante (`'debito_automatico'`) | valor de filtro tipo |
|
|
81
|
+
| `CobroDigital::Transaccion.render(desde, hasta, filtros={})` | método de clase | arma `{ desde, hasta, filtros }`; `desde`/`hasta` a `%Y%m%d` |
|
|
82
|
+
| `CobroDigital::Transaccion.consultar(desde, hasta, filtros={})` | método de clase (constructor) | GET |
|
|
83
|
+
| `CobroDigital::Micrositio` | clase `< Operador` | consulta de actividad de micrositio |
|
|
84
|
+
| `CobroDigital::Micrositio::CONSULTAR_ACTIVIDAD_MICROSITIO_WS` | constante (`'consultar_actividad_micrositio'`) | nombre del método WS |
|
|
85
|
+
| `CobroDigital::Micrositio.consultar_actividad(identificador, buscar, desde, hasta)` | método de clase (constructor) | GET; `desde`/`hasta` a `%Y%m%d` |
|
|
86
|
+
| `CobroDigital::Meta` | clase `< Operador` | agrupa operaciones en una llamada batch al WS `meta` |
|
|
87
|
+
| `CobroDigital::Meta::META_WS` | constante (`'meta'`) | nombre del método WS |
|
|
88
|
+
| `CobroDigital::Meta.transaction(desde, hasta, filtros={})` | método de clase | helper que arma una `Transaccion.consultar` con filtro tipo=ingreso por default |
|
|
89
|
+
| `CobroDigital::Meta.render(objs)` | método de clase | indexa N operaciones en `{ 0 => …, 1 => … }` |
|
|
90
|
+
| `CobroDigital::Meta.meta(objs)` | método de clase (constructor) | POST; `render: render(objs)` |
|
|
91
|
+
| `CobroDigital::VERSION` | constante (`'1.9.0'`) | versión de la gema (`lib/cobro_digital/version.rb`) |
|
|
92
|
+
|
|
93
|
+
## 3. Inferencias
|
|
94
|
+
|
|
95
|
+
| inferencia | confidence | a verificar |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `Client#requests` es atributo público pero no se inicializa ni se usa en el código leído | inferred | ¿atributo muerto o lo setea un consumidor externo? |
|
|
98
|
+
| `Client#pagadores/boletas/transacciones/micrositios` se inicializan a `[]` pero no se leen ni escriben en `lib/**` | inferred | acumuladores planeados sin uso actual |
|
|
99
|
+
| `Pagador.estructura_de_datos` y `Pagador::CONSULTAR_ESTRUCTURA_PAGADORES_WS` no figuran en el README | declared | superficie real, no documentada para el humano |
|
|
100
|
+
| El comentario `@with_handshake` comentado en `Client#initialize` sugiere un handshake opcional descartado | inferred | confirmar que el handshake es siempre-on (hoy lo es vía `#comercio`) |
|
|
101
|
+
|
|
102
|
+
## 4. Cobertura y fronteras
|
|
103
|
+
|
|
104
|
+
- **Cobertura:** total sobre `lib/**` (8 archivos). Todos los símbolos top-level del namespace `CobroDigital` están listados.
|
|
105
|
+
- **Fuera de alcance (otra capa):** el contrato del payload que cada operación envía al WS y la forma de la respuesta cruda → `docs/consumed/cobrodigital.md` (RFC-018). El significado de negocio de cada operación → `docs/glossary/` (RFC-009, `arch-enrich`).
|
|
106
|
+
- **Sin dependencia de ActiveSupport (desde v1.9.0):** el código usa solo stdlib (`to_s.empty?` en `Client#initialize`, `Net::HTTP::Post/Get` en `Client#https_client`). La gema ya no asume Rails → ver `docs/topology/topology.md`.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Test — cobro_digital
|
|
2
|
+
|
|
3
|
+
> meta: artefacto · RFC-013 · generado arch-structure + arch-enrich · anclado a v1.9.0 · inventario estructural (§a-§d) + §e-§h enriquecidos
|
|
4
|
+
|
|
5
|
+
## 1. Resumen
|
|
6
|
+
|
|
7
|
+
Suite RSpec (`spec/cobro_digital_spec.rb`) que cubre la versión, los constructores de las operaciones (`Pagador`/`Boleta`/`Transaccion`) y el parser `Operador#parse_response`. No cubre el transporte real (SOAP/HTTPS) — requiere doble del WS.
|
|
8
|
+
|
|
9
|
+
## 2. §a Suites, frameworks y niveles
|
|
10
|
+
|
|
11
|
+
| framework | versión | dónde |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| RSpec | `~> 3.13` (dev-dep en `cobro_digital.gemspec`) | `.rspec`, `spec/`, `Rakefile` (`RSpec::Core::RakeTask`) |
|
|
14
|
+
|
|
15
|
+
| suite (archivo) | nivel | propósito | tags |
|
|
16
|
+
|---|---|---|---|
|
|
17
|
+
| `spec/cobro_digital_spec.rb` | unit | versión · constructores de operaciones (webservice/http_method/render/fechas) · `parse_response` (éxito y `resultado=false`) | — |
|
|
18
|
+
|
|
19
|
+
## 3. §b Comando de corrida
|
|
20
|
+
|
|
21
|
+
| contexto | comando |
|
|
22
|
+
|---|---|
|
|
23
|
+
| local | `bundle exec rspec` |
|
|
24
|
+
| vía rake (default task) | `bundle exec rake` → `:spec` (`Rakefile`) |
|
|
25
|
+
| CI | GitHub Actions `.github/workflows/main.yml` — `bundle exec rspec` sobre Ruby 2.7 en PRs y push a `master` |
|
|
26
|
+
|
|
27
|
+
Config RSpec (`.rspec`): `--format documentation --color`.
|
|
28
|
+
|
|
29
|
+
## 4. §c Fixtures / Factories
|
|
30
|
+
|
|
31
|
+
Ninguna. No hay `spec/factories/`, `spec/fixtures/` ni FactoryBot. `spec/spec_helper.rb` solo agrega `lib` al `$LOAD_PATH` y requiere `cobro_digital`. El doble del sobre del WS para `parse_response` es un `Struct` anónimo vía `let` (sin constante leaky).
|
|
32
|
+
|
|
33
|
+
## 5. §d Configuración de coverage
|
|
34
|
+
|
|
35
|
+
Ninguna. No hay SimpleCov ni `.simplecov` ni umbral declarado.
|
|
36
|
+
|
|
37
|
+
## 6. §e Gaps de cobertura
|
|
38
|
+
|
|
39
|
+
| dominio / flujo | cubierto | nota |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `CobroDigital::VERSION` presente | sí | — |
|
|
42
|
+
| construcción de operaciones (`Pagador.crear/.verificar`, `Boleta.generar`, `Transaccion.consultar`) | **sí** | verifica `webservice`, `http_method`, `render`, `request` y formateo `%Y%m%d` |
|
|
43
|
+
| `Operador#parse_response` | **sí** | respuesta exitosa (`resultado/log/datos`, rescue por fila) y `resultado=false` |
|
|
44
|
+
| `Micrositio`/`Meta` | **no** | constructores sin test directo |
|
|
45
|
+
| selección de transporte SOAP/HTTPS (`Client#call`, `soap_client`, `https_client`) | **no** | requiere doble de Savon/`Net::HTTP` |
|
|
46
|
+
| guard de `client_to_use` inválido (`ArgumentError`) | **no** | agregado en v1.9.0, sin test aún |
|
|
47
|
+
|
|
48
|
+
## 7. §f Contract-assessment
|
|
49
|
+
|
|
50
|
+
| contrato público | test que lo cubre | estado |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| interfaz (`docs/interface/`) — constructores + `parse_response` | sí (parcial) | cubre la construcción y el parseo; falta el transporte |
|
|
53
|
+
| dependencias consumidas (`docs/consumed/`) — payloads/parseo del WS | parcial | `parse_response` cubierto; el envío real (Savon) sin contract-test |
|
|
54
|
+
| errores | n/a | la gema no define errores propios |
|
|
55
|
+
|
|
56
|
+
## 8. §g Link a incidente
|
|
57
|
+
|
|
58
|
+
`—`. No hay tests de regresión atados a incidentes.
|
|
59
|
+
|
|
60
|
+
## 9. §h PII en fixtures/factories
|
|
61
|
+
|
|
62
|
+
Sin fixtures ni factories → **sin PII en datos de prueba**. Los tests usan datos sintéticos triviales (`'Nombre' => 'Juan'`, `'id'`, números). Si a futuro se agregan factories de pagador, clasificar como **PII** (nombre/documento/e-mail/teléfono) — nunca versionar valores reales.
|
|
63
|
+
|
|
64
|
+
## 10. Cobertura y fronteras
|
|
65
|
+
|
|
66
|
+
- **Cobertura:** total sobre `spec/` (1 archivo) + §e-§h enriquecidos.
|
|
67
|
+
- **Fuera de alcance:** el transporte real (SOAP vía Savon, HTTPS vía `Net::HTTP`) no se ejercita — necesita un doble del WS; candidato a contract-test.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Topología — cobro_digital
|
|
2
|
+
|
|
3
|
+
> meta: artefacto · RFC-006 · generado arch-structure · anclado a v1.9.0 · cobertura total de deps declaradas
|
|
4
|
+
|
|
5
|
+
## 1. Resumen
|
|
6
|
+
|
|
7
|
+
Gema-adaptador de un solo salto: el consumidor la usa para hablar con el WS externo de CobroDigital. Una dependencia de runtime (`savon`) para el transporte SOAP; el transporte HTTPS alternativo usa `Net::HTTP` de la stdlib. **No depende de ActiveSupport** (desde v1.9.0 usa solo stdlib).
|
|
8
|
+
|
|
9
|
+
## 2. §a Dependencias
|
|
10
|
+
|
|
11
|
+
| nombre | versión | rol |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `savon` | `~> 2.12.1` | runtime — cliente SOAP hacia el WS (`Client#soap_client`) |
|
|
14
|
+
| `net/http` · `uri` · `digest` · `json` | stdlib Ruby | runtime — transporte HTTPS, parseo de URI, handshake MD5, (de)serialización JSON (requeridos explícitamente en `lib/cobro_digital.rb`) |
|
|
15
|
+
| `rake` | `>= 13.2.1` | desarrollo |
|
|
16
|
+
| `rspec` | `~> 3.13` | desarrollo (suite) |
|
|
17
|
+
|
|
18
|
+
> **Ruby:** `required_ruby_version = ['>= 2.7', '< 3.0']` — el stack `savon ~> 2.12.1` (httpi 2.x usa `URI.escape`, removido en Ruby 3.0) no corre en 3.0+. El único consumer (wispro_cloud) usa Ruby 2.7.6.
|
|
19
|
+
|
|
20
|
+
## 3. §b Grafo
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
flowchart LR
|
|
24
|
+
Host["Host (consumidor)"] -->|usa la gema| Gem["cobro_digital"]
|
|
25
|
+
Gem -->|SOAP vía savon| WS["WS CobroDigital ws3"]
|
|
26
|
+
Gem -->|HTTPS vía Net HTTP stdlib| WS
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 4. §c Modos de ejecución / transporte
|
|
30
|
+
|
|
31
|
+
| modo | cómo se elige | cliente |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| SOAP (default) | `client_to_use = 'soap'` si no se pasa `:con_client` | `savon` → `webservice_cobrodigital` |
|
|
34
|
+
| HTTPS | `con_client: CobroDigital::HTTPS` | `Net::HTTP::Post`/`Net::HTTP::Get` directo |
|
|
35
|
+
|
|
36
|
+
Un `con_client` que no esté en `CLIENTS` (`['soap','https']`) levanta `ArgumentError` en `Client#initialize`.
|
|
37
|
+
|
|
38
|
+
## 5. Cobertura y fronteras
|
|
39
|
+
|
|
40
|
+
- **Cobertura:** total sobre las deps declaradas en `cobro_digital.gemspec` + las de stdlib requeridas en `lib/**`.
|
|
41
|
+
- **ActiveSupport eliminado (v1.9.0):** las únicas dos APIs de AS (`present?`, `constantize`) se reemplazaron por stdlib (`to_s.empty?`, `Net::HTTP::Post/Get`). La gema ya no asume Rails. (Los ejemplos del README que usan `Date#+`/`.days` son ilustrativos del host, no de la gema.)
|
|
42
|
+
- **Sin `Gemfile.lock` versionado:** las versiones resueltas dependen del host; solo el pin del gemspec es contrato. La CI resuelve con `bundler-cache`.
|