├── .github └── workflows │ ├── ci.yml │ └── docs.yml ├── .gitignore ├── .scrutinizer.yml ├── COPYING ├── README.md ├── composer.json ├── composer.lock ├── docs ├── dev │ ├── index.rst │ └── unit-test.rst ├── getting-started │ ├── example.rst │ ├── index.rst │ ├── install.rst │ ├── legal.rst │ └── setup.rst └── index.rst ├── php-cs-fixer.php ├── phpdoc.xml ├── phpstan.neon ├── phpunit.xml ├── src ├── ApiClient.php ├── ApiException.php └── HttpCurlClient.php └── tests ├── bootstrap.php ├── dte_facturacion ├── AbstractDteFacturacion.php ├── BuscarDteTempTest.php ├── DescargarPdfDteTempTest.php ├── EliminarDteTempTest.php ├── EmitirDteTempTest.php ├── GenerarDteRealTest.php └── ListarDtesTempTest.php ├── lce_contabilidad └── AsientoContableTest.php ├── pagos_cobros_masivos ├── AbstractPagosCobrosMasivos.php ├── BuscarCobroDteTempTest.php ├── CrearCobroMasivoProgramadoTest.php ├── EmitirCobroMasivoProgramadoTest.php ├── ListarCobrosDteTempTest.php ├── ListarCobrosMasivosProgramadosTest.php ├── ObtenerCobroDocumentoEmitidoTest.php └── PagarCobroDteTempTest.php └── test.env-dist /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master # Ejecuta pruebas al hacer push en la rama 'master' 7 | env: 8 | env_var: ${{ vars.ENV_CONTEXT_VAR }} 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | php-version: ['8.3'] # Puedes cambiar las versiones según necesites 17 | 18 | steps: 19 | - name: Check out repository code 20 | uses: actions/checkout@v3 21 | 22 | - name: Setup PHP ${{ matrix.php-version }} 23 | uses: shivammathur/setup-php@v2 24 | with: 25 | php-version: ${{ matrix.php-version }} # Configura la versión de PHP desde la matriz 26 | extensions: curl, mbstring, intl, xdebug 27 | tools: composer 28 | 29 | - name: Install Composer dependencies 30 | run: composer install --no-progress --no-suggest 31 | 32 | - name: Run PHP tests dte temp 33 | env: 34 | LIBREDTE_HASH: ${{ secrets.LIBREDTE_HASH }} 35 | LIBREDTE_RUT: ${{ vars.LIBREDTE_RUT }} 36 | run: | 37 | composer tests-readonly 38 | 39 | - name: Upload PHPUnit result report 40 | if: failure() 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: tests-testdox-php_${{ matrix.php-version }}.txt 44 | path: var/tests-testdox.txt 45 | 46 | - name: Upload Coverage Report 47 | uses: actions/upload-artifact@v4 48 | with: 49 | name: tests-coverage-php_${{ matrix.php-version }}.txt 50 | path: var/tests-coverage.txt 51 | 52 | - name: Display PHP version 53 | run: php -v -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | 9 | jobs: 10 | docs: 11 | name: Docs 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Check out repository 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up PHP 19 | uses: shivammathur/setup-php@v2 20 | with: 21 | php-version: '8.3' 22 | 23 | - name: Download phpDocumentor 24 | run: | 25 | mkdir -p tools 26 | wget https://phpdoc.org/phpDocumentor.phar -O tools/phpdocumentor 27 | 28 | - name: Generate Documentation 29 | run: php tools/phpdocumentor run --config=phpdoc.xml 30 | 31 | - name: Create CNAME file 32 | run: echo "api-client-php.docs.libredte.cl" > build/docs/CNAME 33 | 34 | - name: Deploy to GitHub Pages 35 | if: success() 36 | uses: peaceiris/actions-gh-pages@v4 37 | with: 38 | github_token: ${{ secrets.GITHUB_TOKEN }} 39 | publish_dir: ./build/docs 40 | publish_branch: gh-pages 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | tests/test.env 3 | tests/archivos/dte_facturacion/* 4 | 5 | var/ 6 | tools/ 7 | build/ 8 | 9 | prueba-ejemplo.php -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | php: true 3 | 4 | build: 5 | nodes: 6 | analysis: 7 | tests: 8 | override: 9 | - php-scrutinizer-run 10 | - command: composer tests-readonly 11 | coverage: 12 | file: var/tests-coverage.xml 13 | format: clover 14 | environment: 15 | php: 16 | version: 8.3.13 17 | pecl_extensions: 18 | - xdebug 19 | dependencies: 20 | before: 21 | - composer install --no-progress --prefer-dist 22 | 23 | tools: 24 | php_code_sniffer: 25 | enabled: true 26 | config: 27 | standard: PSR12 28 | 29 | filter: 30 | paths: 31 | - src/* 32 | excluded_paths: 33 | - resources/* 34 | - tests/* 35 | - tools/* 36 | - var/* 37 | - vendor/* -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LibreDTE: Cliente de API en PHP 2 | =============================== 3 | 4 | [![CI Workflow](https://github.com/libredte/libredte-api-client-php/actions/workflows/ci.yml/badge.svg?branch=master&event=push)](https://github.com/libredte/libredte-api-client-php/actions/workflows/ci.yml?query=branch%3Amaster) 5 | [![Scrutinizer](https://scrutinizer-ci.com/g/libredte/libredte-api-client-php/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/libredte/libredte-api-client-php/) 6 | [![Coverage](https://scrutinizer-ci.com/g/libredte/libredte-api-client-php/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/libredte/libredte-api-client-php/) 7 | [![Licencia](https://poser.pugx.org/libredte/libredte-api-client/license)](https://packagist.org/packages/libredte/libredte-api-client) 8 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FLibreDTE%2Flibredte-api-client-php.svg?type=shield&issueType=license)](https://app.fossa.com/projects/git%2Bgithub.com%2FLibreDTE%2Flibredte-api-client-php?ref=badge_shield&issueType=license) 9 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FLibreDTE%2Flibredte-api-client-php.svg?type=shield&issueType=security)](https://app.fossa.com/projects/git%2Bgithub.com%2FLibreDTE%2Flibredte-api-client-php?ref=badge_shield&issueType=security) 10 | [![Descargas Totales](https://poser.pugx.org/libredte/libredte-api-client/downloads)](https://packagist.org/packages/libredte/libredte-api-client) 11 | [![Descargas Mensuales](https://poser.pugx.org/libredte/libredte-api-client/d/monthly)](https://packagist.org/packages/libredte/libredte-api-client) 12 | 13 | Cliente para realizar la integración con los servicios web de [LibreDTE](https://www.libredte.cl) desde PHP. 14 | 15 | Revisa la [documentación](https://api-client-php.docs.libredte.cl/guide/index.html) de la biblioteca para más información, sus características y detalles de su uso. 16 | 17 | Licencia 18 | -------- 19 | 20 | Este programa es software libre: usted puede redistribuirlo y/o modificarlo 21 | bajo los términos de la GNU Lesser General Public License (LGPL) publicada 22 | por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 23 | o (a su elección) cualquier versión posterior de la misma. 24 | 25 | Este programa se distribuye con la esperanza de que sea útil, pero SIN 26 | GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 27 | PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 28 | Public License (LGPL) para obtener una información más detallada. 29 | 30 | Debería haber recibido una copia de la GNU Lesser General Public License 31 | (LGPL) junto a este programa. En caso contrario, consulte 32 | [GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html). 33 | 34 | Enlaces 35 | ------- 36 | 37 | - [Sitio web LibreDTE](https://www.libredte.cl). 38 | - [Código fuente en GitHub](https://github.com/LibreDTE/libredte-api-client-php). 39 | - [Paquete en Packagist](https://packagist.org/packages/libredte/libredte-api-client). 40 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libredte/libredte-api-client", 3 | "description": "Cliente para realizar la integración con los servicios web de LibreDTE desde PHP.", 4 | "type": "library", 5 | "keywords": ["api", "dte", "sii", "facturación electrónica", "chile"], 6 | "homepage": "https://www.libredte.cl", 7 | "license": "LGPL-3.0+", 8 | "authors": [ 9 | { 10 | "name": "LibreDTE", 11 | "homepage": "https://www.libredte.cl" 12 | } 13 | ], 14 | "support": { 15 | "issues": "https://github.com/LibreDTE/libredte-api-client-php/issues", 16 | "source": "https://github.com/LibreDTE/libredte-api-client-php" 17 | }, 18 | "config": { 19 | "platform": { 20 | "php": "8.2" 21 | } 22 | }, 23 | "require": { 24 | "php": "^8.2 || ^8.3", 25 | "ext-curl": "*" 26 | }, 27 | "require-dev": { 28 | "friendsofphp/php-cs-fixer": "^3.63", 29 | "phpstan/phpstan": "^1.12", 30 | "phpunit/phpunit": "^11.3", 31 | "vlucas/phpdotenv": "^5.6" 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "libredte\\api_client\\": "src/", 36 | "libredte\\dte_facturacion\\": "tests/dte_facturacion/", 37 | "libredte\\pagos_cobros_masivos\\": "tests/pagos_cobros_masivos/" 38 | } 39 | }, 40 | "scripts": { 41 | "docs": "php tools/phpdocumentor run --config=phpdoc.xml", 42 | "tests": "XDEBUG_MODE=coverage vendor/bin/phpunit --configuration=phpunit.xml", 43 | "tests-dte": "XDEBUG_MODE=coverage vendor/bin/phpunit --configuration=phpunit.xml --testsuite dte-facturacion", 44 | "tests-contab": "XDEBUG_MODE=coverage vendor/bin/phpunit --configuration=phpunit.xml --testsuite lce-contabilidad", 45 | "tests-cobros": "XDEBUG_MODE=coverage vendor/bin/phpunit --configuration=phpunit.xml --testsuite pagos-cobros-mas", 46 | "tests-readonly": "XDEBUG_MODE=coverage vendor/bin/phpunit --configuration=phpunit.xml --filter 'testBuscarDteTemp|testDescargarPdfDteTemp|testEmitirDteTemp|testEliminarDteTemp|testListarDteTemp|testListarCobrosDteTemp|testBuscarCobroDteTemp'", 47 | "phpcs-fix": "php-cs-fixer fix -v --config=php-cs-fixer.php .", 48 | "phpcs-fix-dry-run": "php-cs-fixer fix -v --dry-run --diff --config=php-cs-fixer.php .", 49 | "phpstan": "phpstan analyse --configuration=phpstan.neon --memory-limit=1G", 50 | "phpstan-export": "phpstan analyse --configuration=phpstan.neon --level 9 --generate-baseline" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /docs/dev/index.rst: -------------------------------------------------------------------------------- 1 | Desarrollo 2 | ========== 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | unit-test -------------------------------------------------------------------------------- /docs/dev/unit-test.rst: -------------------------------------------------------------------------------- 1 | Pruebas unitarias 2 | ================= 3 | 4 | .. important:: 5 | Al ejecutar pruebas, deberás tener configuradas las variables de entorno necesarias en el archivo test.env. Favor de duplicar test.env-dist, cambiar su nombre a test.env y rellenar las variables necesarias. 6 | 7 | Antes de empezar, debes configurar las siguientes variables de entorno: 8 | 9 | .. code-block:: shell 10 | LIBREDTE_URL="https://libredte.cl" 11 | LIBREDTE_HASH="hash-libredte" 12 | LIBREDTE_RUT="66666666-6" 13 | 14 | Para ejecutar las pruebas unitarias se necesita tener instaladas las dependencias de composer, y para hacer todas las pruebas, ejecutar lo siguiente: 15 | 16 | .. code-block:: shell 17 | ./vendor/bin/phpunit 18 | 19 | También es posible ejecutar una prueba específica indicando el test. Ejemplo: 20 | 21 | .. code-block:: shell 22 | ./vendor/bin/phpunit --filter testEmitirDteTemp --no-coverage 23 | -------------------------------------------------------------------------------- /docs/getting-started/example.rst: -------------------------------------------------------------------------------- 1 | Ejemplo 2 | ======= 3 | 4 | Ejemplo de Generar un DTE temporal 5 | ------------------------------- 6 | 7 | Antes de probar, integrar y/o utilizar el cliente de API, necesitas haber definido previamente las variables de entorno. 8 | 9 | .. seealso:: 10 | Para más información sobre este paso, referirse al la guía en Configuración. 11 | 12 | El siguiente es un ejemplo básico de cómo emitir un DTE usando el cliente de API de LibreDTE: 13 | 14 | .. code-block:: php 15 | [ 31 | 'IdDoc' => [ 32 | 'TipoDTE' => 33, 33 | ], 34 | 'Emisor' => [ 35 | 'RUTEmisor' => $emisor_rut, 36 | ], 37 | 'Receptor' => [ 38 | 'RUTRecep' => '60803000-K', 39 | 'RznSocRecep' => 'Servicio de Impuestos Internos (SII)', 40 | 'GiroRecep' => 'Administración Pública', 41 | 'Contacto' => '+56 2 3252 5575', 42 | 'CorreoRecep' => 'facturacionmipyme@sii.cl', 43 | 'DirRecep' => 'Teatinos 120', 44 | 'CmnaRecep' => 'Santiago', 45 | ], 46 | ], 47 | 'Detalle' => [ 48 | [ 49 | //'IndExe' => 1, // para items exentos 50 | 'NmbItem' => 'Asesoría de LibreDTE', 51 | 'QtyItem' => 1, 52 | 'PrcItem' => 1000, 53 | ], 54 | ], 55 | 'Referencia' => [ 56 | [ 57 | 'TpoDocRef' => 801, 58 | 'FolioRef' => 'OC123', 59 | 'FchRef' => '2015-10-01', 60 | ] 61 | ], 62 | ]; 63 | 64 | # Recurso a consumir. 65 | $resource = '/dte/documentos/emitir'; 66 | 67 | # Se efectua la solicitud HTTP y se guarda la respuesta. 68 | $response = $client->post($resource, $datos); 69 | 70 | # Código del response 71 | echo "Status: ".$response['status']['code']."\n"; 72 | 73 | # Despliegue del body. 74 | if ($response['status']['code'] != 200) { 75 | echo $response['body']."\n"; # Si falla, el body contendrá el mensaje de error. 76 | } else { 77 | echo "\nDTEs Temporales: \n"; 78 | echo "\n",'FACTURAR DTE TEMP: ',json_encode($response['body']),"\n"; 79 | } 80 | 81 | .. seealso:: 82 | Para saber más sobre los parámetros posibles y el cómo consumir las API, referirse a la `documentación de LibreDTE. `_ 83 | -------------------------------------------------------------------------------- /docs/getting-started/index.rst: -------------------------------------------------------------------------------- 1 | Empezando 2 | ========= 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | legal 8 | install 9 | setup 10 | example -------------------------------------------------------------------------------- /docs/getting-started/install.rst: -------------------------------------------------------------------------------- 1 | Instalación 2 | =========== 3 | 4 | Desde Composer: 5 | 6 | Para obtener el cliente de la API, debe tener composer instalado, y ejecutar el siguiente comando en consola para instalar el cliente de API en PHP: 7 | 8 | .. code-block:: shell 9 | composer require libredte/libredte-api-client 10 | 11 | Desde GitHub: 12 | 13 | Si estás utilizando la versión de GitHub, deberás instalar los paquetes necesarios para su funcionamiento. Para ello debes ejecutar lo siguiente en su lugar desde la carpeta del proyecto: 14 | 15 | .. code-block:: shell 16 | composer install 17 | 18 | .. important:: 19 | Si el segundo paso no funciona, remueve composer.lock y vuelve a ejecutar composer install. 20 | 21 | Requerimientos 22 | -------------- 23 | 24 | - PHP 7.3 o superior. 25 | 26 | - Extensiones de PHP: 27 | - curl. 28 | - ext-curl. 29 | - guzzlehttp. 30 | - phpdotenv. 31 | - phpdocumentor. -------------------------------------------------------------------------------- /docs/getting-started/legal.rst: -------------------------------------------------------------------------------- 1 | Términos y Condiciones de Uso 2 | ============================= 3 | 4 | Este programa es software libre: usted puede redistribuirlo y/o modificarlo 5 | bajo los términos de la GNU Lesser General Public License (LGPL) publicada 6 | por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 7 | o (a su elección) cualquier versión posterior de la misma. 8 | 9 | Este programa se distribuye con la esperanza de que sea útil, pero SIN 10 | GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 11 | PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 12 | Public License (LGPL) para obtener una información más detallada. 13 | 14 | Debería haber recibido una copia de la GNU Lesser General Public License 15 | (LGPL) junto a este programa. En caso contrario, consulte 16 | `GNU Lesser General Public License `_. 17 | 18 | .. important:: 19 | 20 | Para utilizar el cliente de API de LibreDTE, necesitará una cuenta de LibreDTE. Al usar dicha cuenta, es obligatorio leer y aceptar por completo los `términos y condiciones de uso `_. 21 | -------------------------------------------------------------------------------- /docs/getting-started/setup.rst: -------------------------------------------------------------------------------- 1 | Configuración 2 | ============= 3 | 4 | Para utilizar el cliente de API de LibreDTE, se debe tener un token de usuario, generado y obtenido desde la cuenta de LibreDTE. 5 | 6 | .. important:: 7 | El archivo test.env sólo sirve para usar con los test. Por lo que se deberán definir las variables de entorno por los siguientes dos métodos: Directo por consola (temporal), o definirlas directamente en el entorno (persistente). 8 | 9 | En Linux o MacOS: 10 | ----------------- 11 | 12 | El token se almacena en una variable de entorno. Para almacenar en una variable de entorno, se debe escribir lo siguiente en consola. 13 | 14 | 15 | .. code-block:: shell 16 | export LIBREDTE_URL="https://libredte.cl" 17 | export LIBREDTE_HASH="aqui-tu-hash-de-libredte" 18 | export LIBREDTE_RUT="66666666-6" 19 | 20 | - ``LIBREDTE_HASH`` es una cadena de varios caracteres. Almacena ese token en un lugar seguro y no lo compartas con nadie. 21 | - ``LIBREDTE_RUT`` contiene tu RUT asociado a la cuenta de LibreDTE, con Dígito Verificador. 22 | 23 | Introducir en consola las variables de entorno almacena temporalmente las variables, y alternativamente, se puede modificar el archivo de configuración de shell en Linux (que se explicará a continuación), y añadir al final del archivo los comandos previamente introducidos. Añadir variables de entorno de esta forma es más persistente y no se repite su definición. 24 | 25 | - Si se usa Linux, se deben añadir al archivo ``~/.bashrc`` los comandos previamente definidos. 26 | - Si se usa MacOS, se deben añadir al archivo ``~/.zshrc``. 27 | 28 | El paso siguiente sólo se hace para usuarios de MacOS. Por último, ejecutar el comando en cuestión para efectuar los cambios. 29 | 30 | .. code-block:: shell 31 | source ~/.zshrc 32 | 33 | En Windows: 34 | ----------- 35 | 36 | Para almacenar en una variable de entorno en Windows, hay varias alternativas. La primera es utilizando cmd, y para almacenarlas utilizando cmd, ejecuta en el buscador de Windows "cmd", y ejecuta los siguientes comandos: 37 | 38 | .. code-block:: shell 39 | setx LIBREDTE_URL "https://libredte.cl" 40 | setx LIBREDTE_HASH "aqui-tu-hash-de-libredte" 41 | setx LIBREDTE_RUT "66666666-6" 42 | 43 | También se pueden definir utilizando Windows PowerShell, de una manera similar. Ejecuta en el buscador de Windows "PowerShell", y ejecuta los siguientes comandos: 44 | 45 | .. code-block:: shell 46 | $Env:LIBREDTE_URL="https://libredte.cl" 47 | $Env:LIBREDTE_HASH="aqui-tu-hash-de-libredte" 48 | $Env:LIBREDTE_RUT="66666666-6" 49 | 50 | 51 | Como alternativa para almacenar las variables de manera persistente, debes seguir los siguientes pasos: 52 | 53 | 1. Abre el Panel de Control > Sistema > Configuración avanzada del sistema. 54 | 2. En la pestaña Opciones avanzadas, selecciona Variables de entorno. 55 | 3. Añade o modifica las variables en la sección de "Variables de usuario" o "Variables del sistema". 56 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Docs: libredte-api-client-php 2 | ============== 3 | 4 | .. image:: https://github.com/libredte/libredte-api-client-php/actions/workflows/ci.yml/badge.svg?branch=master&event=push 5 | :target: https://github.com/libredte/libredte-api-client-php/actions/workflows/ci.yml?query=branch%3Amaster 6 | 7 | .. image:: https://scrutinizer-ci.com/g/libredte/libredte-api-client-php/badges/quality-score.png?b=master 8 | :target: https://scrutinizer-ci.com/g/libredte/libredte-api-client-php/ 9 | 10 | .. image:: https://scrutinizer-ci.com/g/libredte/libredte-api-client-php/badges/coverage.png?b=master 11 | :target: https://scrutinizer-ci.com/g/libredte/libredte-api-client-php/ 12 | 13 | .. image:: https://poser.pugx.org/libredte/libredte-api-client/license 14 | :target: https://packagist.org/packages/libredte/libredte-api-client 15 | 16 | .. image:: https://app.fossa.com/api/projects/git%2Bgithub.com%2FLibreDTE%2Flibredte-api-client-php.svg?type=shield&issueType=license 17 | :target: https://app.fossa.com/projects/git%2Bgithub.com%2FLibreDTE%2Flibredte-api-client-php?ref=badge_shield&issueType=license 18 | 19 | .. image:: https://app.fossa.com/api/projects/git%2Bgithub.com%2FLibreDTE%2Flibredte-api-client-php.svg?type=shield&issueType=security 20 | :target: https://app.fossa.com/projects/git%2Bgithub.com%2FLibreDTE%2Flibredte-api-client-php?ref=badge_shield&issueType=security 21 | 22 | .. image:: https://poser.pugx.org/libredte/libredte-api-client/downloads 23 | :target: https://packagist.org/packages/libredte/libredte-api-client 24 | 25 | .. image:: https://poser.pugx.org/libredte/libredte-api-client/d/monthly 26 | :target: https://packagist.org/packages/libredte/libredte-api-client 27 | 28 | Bienvenido a la documentación del cliente de API de LibreDTE. 29 | 30 | .. toctree:: 31 | :titlesonly: 32 | 33 | getting-started/index 34 | features/index 35 | dev/index 36 | 37 | LibreDTE es un proyecto que tiene como objetivo emitir y manejar los Documentos Tributarios Electrónicos con mucha más facilidad. 38 | 39 | Aquí podrás encontrar la biblioteca escrita en lenguaje PHP para llamar a las APIs de LibreDTE. Este cliente normalmente requiere una cuenta en el SII para poder manejar las DTE que necesites gestionar o emitir. 40 | 41 | Enlaces 42 | ------- 43 | 44 | - `Sitio web LibreDTE `_ 45 | - `Código fuente en GitHub `_ 46 | - `Paquete en Packagist `_ 47 | - `Documentación `_ -------------------------------------------------------------------------------- /php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | /** 25 | * Archivo de configuración para PHP CS Fixer. 26 | */ 27 | 28 | use PhpCsFixer\Config; 29 | use PhpCsFixer\Finder; 30 | 31 | $dir = __DIR__; 32 | 33 | $finder = Finder::create() 34 | ->in($dir) 35 | ->name('*.php') 36 | ->exclude('vendor'); 37 | 38 | return (new Config()) 39 | // Permitir reglas riesgosas que cambian la lógica del código. 40 | ->setRiskyAllowed(true) 41 | // Basado en PSR-12, la última recomendación de estilo. 42 | ->setRules([ 43 | '@PSR12' => true, 44 | // Añadir "declare(strict_types=1);" a los archivos. 45 | // Esto los añade así true, 48 | // Indentar con espacios. 49 | 'indentation_type' => true, 50 | // Ordenar los "use" alfabéticamente. 51 | 'ordered_imports' => [ 52 | 'sort_algorithm' => 'alpha', 53 | ], 54 | // Eliminar imports no usados. 55 | 'no_unused_imports' => true, 56 | // Un import por declaración. 57 | 'single_import_per_statement' => true, 58 | // Convertir arreglos a la sintaxis corta "[]". 59 | 'array_syntax' => [ 60 | 'syntax' => 'short', 61 | ], 62 | // Añadir comas finales en arreglos de varias líneas. 63 | 'trailing_comma_in_multiline' => true, 64 | // Separar constantes y propiedades. 65 | 'class_attributes_separation' => [ 66 | 'elements' => [ 67 | 'const' => 'one', 68 | 'property' => 'one', 69 | 'method' => 'one', 70 | ], 71 | ], 72 | // Reemplazar strpos con un return de bool. 73 | // Ejemplo usar: str_contains(). 74 | 'modernize_strpos' => true, 75 | // Convertir funciones anónimas a funciones flecha. 76 | 'use_arrow_functions' => true, 77 | // Usar constructores de PHPUnit en lugar de métodos de fábrica. 78 | 'php_unit_construct' => true, 79 | // Usar aserciones más estrictas en PHPUnit. 80 | // Ejemplo: usar assertSame() en vez de assertEquals(). 81 | 'php_unit_strict' => true, 82 | ]) 83 | ->setLineEnding("\n") 84 | ->setCacheFile($dir . '/var/cache/php-cs-fixer.cache') 85 | ->setFinder($finder) 86 | ; 87 | -------------------------------------------------------------------------------- /phpdoc.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | LibreDTE API Client 9 | 10 | build/docs 11 | var/cache/phpdocumentor 12 | 13 | 14 | latest 15 | 16 | libredte-api-client 17 | 18 | src 19 | 20 | 21 | php 22 | 23 | false 24 | 25 | TODO 26 | FIXME 27 | WARNING 28 | NOTE 29 | 30 | 31 | 32 | 33 | docs 34 | 35 | /guide 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | # Nivel de revisión, desde básico (1) a muy completo (9). 3 | level: 5 4 | # Directorios de código fuente que se revisarán. 5 | paths: 6 | - src 7 | - tests -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | src 28 | 29 | 30 | 31 | 32 | tests/dte_facturacion 33 | 34 | 35 | tests/lce_contabilidad 36 | 37 | 38 | tests/pagos_cobros_masivos 39 | 40 | 41 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/ApiClient.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | namespace libredte\api_client; 25 | 26 | /** 27 | * Clase ApiClient para la integración con la API de LibreDTE. 28 | * 29 | * Proporciona funcionalidades para realizar peticiones HTTP a la API de 30 | * LibreDTE, incluyendo métodos para realizar solicitudes GET y POST. 31 | */ 32 | class ApiClient 33 | { 34 | /** 35 | * La URL base de la API de LibreDTE. 36 | * 37 | * @var string 38 | */ 39 | private $api_url = 'https://libredte.cl'; 40 | 41 | /** 42 | * El prefijo para las rutas de la API. 43 | * 44 | * @var string 45 | */ 46 | private $api_prefix = '/api'; 47 | 48 | /** 49 | * Valores por defecto de la cabecera que se pasarán a cURL. 50 | * 51 | * @var array 52 | */ 53 | private $headers = [ 54 | 'User-Agent' => 'LibreDTE: Cliente de API en PHP.', 55 | 'Content-Type' => 'application/json', 56 | 'Accept' => 'application/json', 57 | ]; 58 | 59 | /** 60 | * Objeto para manejar las conexiones HTTP mediante cURL. 61 | * 62 | * @var HttpCurlClient 63 | */ 64 | private $client; 65 | 66 | /** 67 | * Constructor de la clase ApiClient. 68 | * 69 | * Inicializa el cliente con las credenciales y la URL de la API. Si no se 70 | * proporcionan, se intentará obtener desde las variables de entorno. 71 | * 72 | * @param string|null $hash Hash de autenticación del usuario en LibreDTE. 73 | * @param string|null $url URL base de la API de LibreDTE. 74 | * @throws ApiException si el hash de autenticación no está presente. 75 | */ 76 | public function __construct(string $hash = null, string $url = null) 77 | { 78 | $hash = $hash ?: $this->env('LIBREDTE_HASH'); 79 | if (!$hash) { 80 | throw new ApiException(message: 'LIBREDTE_HASH missing'); 81 | } 82 | $this->headers['Authorization'] = 'Basic ' . base64_encode( 83 | $hash . ':X' 84 | ); 85 | $this->api_url = $url ?: $this->env('LIBREDTE_URL') ?: $this->api_url; 86 | $this->client = new HttpCurlClient(); 87 | } 88 | 89 | /** 90 | * Establece una cabecera para las solicitudes HTTP. 91 | * 92 | * Permite definir un valor para una cabecera específica que se incluirá en 93 | * todas las solicitudes HTTP realizadas por la instancia del cliente. 94 | * 95 | * @param string $name Nombre de la cabecera. 96 | * @param mixed $value Valor de la cabecera. 97 | * @return void 98 | */ 99 | public function setHeader(string $name, mixed $value): void 100 | { 101 | $this->headers[$name] = $value; 102 | } 103 | 104 | /** 105 | * Configura las opciones de SSL para las conexiones HTTP. 106 | * 107 | * Este método permite activar o desactivar la verificación del certificado 108 | * SSL del servidor. 109 | * 110 | * @param boolean $sslcheck Activar o desactivar la verificación del 111 | * certificado SSL. 112 | * @return void 113 | */ 114 | public function setSSL($sslcheck = true): void 115 | { 116 | $this->client->setSSL($sslcheck); 117 | } 118 | 119 | /** 120 | * Realiza una solicitud POST a la API de LibreDTE. 121 | * 122 | * Envia datos a un recurso específico de la API utilizando el método POST. 123 | * 124 | * @param string $resource El recurso de la API a solicitar. 125 | * @param mixed|null $data Los datos a enviar en la solicitud POST. 126 | * @param array $headers Encabezados adicionales para la solicitud. 127 | * @return array Respuesta de la API. 128 | */ 129 | public function post(string $resource, mixed $data = null, array $headers = []): array|bool 130 | { 131 | $headers = array_merge($this->headers, $headers); 132 | return $this->client->query( 133 | method: 'POST', 134 | url: $this->api_url . $this->api_prefix . $resource, 135 | data: $data, 136 | headers: $headers 137 | ); 138 | } 139 | 140 | /** 141 | * Realiza una solicitud GET a la API de LibreDTE. 142 | * 143 | * Recupera datos de un recurso específico de la API utilizando el método 144 | * GET. 145 | * 146 | * @param string $resource El recurso de la API a solicitar. 147 | * @param mixed|null $data Los datos a enviar en la solicitud GET. 148 | * @param array $headers Encabezados adicionales para la solicitud. 149 | * @return array Respuesta de la API. 150 | */ 151 | public function get(string $resource, mixed $data = null, array $headers = []): array|bool 152 | { 153 | $headers = array_merge($this->headers, $headers); 154 | return $this->client->query( 155 | method: 'GET', 156 | url: $this->api_url . $this->api_prefix . $resource, 157 | data: $data, 158 | headers: $headers 159 | ); 160 | } 161 | 162 | /** 163 | * Obtiene el valor de una variable de entorno. 164 | * 165 | * Este método es utilizado internamente para obtener configuraciones 166 | * como el hash de autenticación o la URL base de la API. 167 | * 168 | * @param string $name Nombre de la variable de entorno. 169 | * @return mixed|null Valor de la variable de entorno o null si no está 170 | * definida. 171 | */ 172 | private function env($name): mixed 173 | { 174 | return function_exists('env') ? env($name) : getenv($name); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/ApiException.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | namespace libredte\api_client; 25 | 26 | /** 27 | * Clase ApiException para la gestión de excepciones en el cliente de la API 28 | * de LibreDTE. 29 | * 30 | * Esta clase extiende la clase Exception estándar de PHP y se utiliza para 31 | * manejar errores específicos que pueden ocurrir durante las interacciones 32 | * con la API de LibreDTE. 33 | * Las instancias de ApiException pueden incluir información adicional 34 | * relevante para los errores de la API. 35 | */ 36 | class ApiException extends \Exception 37 | { 38 | // Aquí van los métodos y propiedades de la clase 39 | } 40 | -------------------------------------------------------------------------------- /src/HttpCurlClient.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | namespace libredte\api_client; 25 | 26 | /** 27 | * Clase HttpCurlClient para realizar consultas HTTP utilizando cURL. 28 | * 29 | * Esta clase proporciona una interfaz para realizar peticiones HTTP, como GET 30 | * y POST, utilizando cURL. Ofrece configuración de SSL y manejo de errores de 31 | * cURL. 32 | */ 33 | class HttpCurlClient 34 | { 35 | /** 36 | * Indica si se debe validar el certificado SSL del servidor. 37 | * 38 | * @var boolean 39 | */ 40 | private $sslcheck = true; 41 | 42 | /** 43 | * Historial de errores de las consultas HTTP mediante cURL. 44 | * 45 | * @var array 46 | */ 47 | private $errors = []; 48 | 49 | /** 50 | * Devuelve los errores ocurridos en las peticiones HTTP. 51 | * 52 | * Este método devuelve un array con los errores generados por cURL en las 53 | * peticiones HTTP realizadas. 54 | * 55 | * @return array Lista de errores de cURL. 56 | */ 57 | public function getErrors(): array 58 | { 59 | return $this->errors; 60 | } 61 | 62 | /** 63 | * Devuelve el último error ocurrido en una petición HTTP. 64 | * 65 | * Este método devuelve el último error generado por cURL en una petición 66 | * HTTP. 67 | * 68 | * @return string Descripción del último error de cURL. 69 | */ 70 | public function getLastError(): string 71 | { 72 | return $this->errors[count($this->errors) - 1]; 73 | } 74 | 75 | /** 76 | * Configura las opciones de SSL para las peticiones HTTP. 77 | * 78 | * Este método permite activar o desactivar la verificación del certificado 79 | * SSL del servidor. 80 | * 81 | * @param boolean $sslcheck Activar o desactivar la verificación del 82 | * certificado SSL. 83 | */ 84 | public function setSSL(bool $sslcheck = true): void 85 | { 86 | $this->sslcheck = $sslcheck; 87 | } 88 | 89 | /** 90 | * Realiza una solicitud HTTP a una URL. 91 | * 92 | * Este método ejecuta una petición HTTP utilizando cURL y devuelve la 93 | * respuesta. 94 | * Soporta varios métodos HTTP como GET, POST, PUT, DELETE, etc. 95 | * 96 | * @param string $method Método HTTP a utilizar. 97 | * @param string $url URL a la que se realiza la petición. 98 | * @param mixed $data Datos a enviar en la petición. 99 | * @param array $headers Cabeceras HTTP a enviar. 100 | * @return array|false Respuesta HTTP o false en caso de error. 101 | */ 102 | public function query( 103 | string $method, 104 | string $url, 105 | mixed $data = [], 106 | array $headers = [] 107 | ): array|bool { 108 | // preparar datos 109 | if ($data && $method != 'GET') { 110 | if (isset($data['@files'])) { 111 | $files = $data['@files']; 112 | unset($data['@files']); 113 | $data = ['@data' => json_encode($data)]; 114 | foreach ($files as $key => $file) { 115 | $data[$key] = $file; 116 | } 117 | } else { 118 | $data = json_encode($data); 119 | $headers['Content-Length'] = strlen($data); 120 | } 121 | } 122 | // inicializar curl 123 | $curl = curl_init(); 124 | // asignar método y datos dependiendo de si es GET u otro método 125 | if ($method == 'GET') { 126 | if (is_array($data)) { 127 | $data = http_build_query($data); 128 | } 129 | if ($data) { 130 | $url = sprintf("%s?%s", $url, $data); 131 | } 132 | } else { 133 | curl_setopt($curl, CURLOPT_POST, 1); 134 | curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); 135 | if ($data) { 136 | curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 137 | } 138 | } 139 | // asignar cabecera 140 | foreach ($headers as $key => &$value) { 141 | $value = $key.': '.$value; 142 | } 143 | // asignar cabecera 144 | curl_setopt($curl, CURLOPT_HTTPHEADER, array_values($headers)); 145 | // realizar consulta a curl recuperando cabecera y cuerpo 146 | curl_setopt($curl, CURLOPT_URL, $url); 147 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 148 | curl_setopt($curl, CURLOPT_HEADER, 1); 149 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->sslcheck); 150 | $response = curl_exec($curl); 151 | if (!$response) { 152 | $this->errors[] = curl_error($curl); 153 | return false; 154 | } 155 | $headers_size = curl_getinfo(handle: $curl, option: CURLINFO_HEADER_SIZE); 156 | // cerrar conexión de curl 157 | curl_close($curl); 158 | // entregar respuesta de la solicitud 159 | $response_headers = $this->parseResponseHeaders( 160 | substr( 161 | string: $response, 162 | offset: 0, 163 | length: $headers_size 164 | ) 165 | ); 166 | $body = substr($response, $headers_size); 167 | $json = json_decode(json: $body, associative: true); 168 | return [ 169 | 'status' => $this->parseResponseStatus($response_headers[0]), 170 | 'header' => $response_headers, 171 | 'body' => $json !== null ? $json : $body, 172 | ]; 173 | } 174 | 175 | /** 176 | * Método que procesa y convierte la cabecera en texto plano a un arreglo 177 | * asociativo. 178 | * 179 | * Convierte las cabeceras HTTP dadas en texto plano a un arreglo 180 | * asociativo. Si una cabecera aparece más de una vez, su valor será un 181 | * arreglo con todos sus valores. 182 | * 183 | * @param string $headers_txt Cabeceras HTTP en formato de texto plano. 184 | * @return array Arreglo asociativo con las cabeceras procesadas. 185 | */ 186 | private function parseResponseHeaders(string $headers_txt): array 187 | { 188 | $headers = []; 189 | $lineas = explode("\n", $headers_txt); 190 | foreach ($lineas as &$linea) { 191 | $linea = trim($linea); 192 | if (!isset($linea[0])) { 193 | continue; 194 | } 195 | if (strpos($linea, ':')) { 196 | list($key, $value) = explode( 197 | separator: ':', 198 | string: $linea, 199 | limit: 2 200 | ); 201 | } else { 202 | $key = 0; 203 | $value = $linea; 204 | } 205 | $key = trim(strval($key)); 206 | $value = trim($value); 207 | if (!isset($headers[$key])) { 208 | $headers[$key] = $value; 209 | } elseif (!is_array($headers[$key])) { 210 | $aux = $headers[$key]; 211 | $headers[$key] = [$aux, $value]; 212 | } else { 213 | $headers[$key][] = $value; 214 | } 215 | } 216 | return $headers; 217 | } 218 | 219 | /** 220 | * Método que procesa la línea de estado de la respuesta HTTP y extrae 221 | * información útil. 222 | * 223 | * Extrae el protocolo, el código de estado y el mensaje del estado de la 224 | * línea de respuesta HTTP. 225 | * Útil para entender y manejar la respuesta HTTP. 226 | * 227 | * @param array|string $response_line Línea de respuesta HTTP. 228 | * @return array Arreglo con información del estado, incluyendo protocolo, 229 | * código y mensaje. 230 | */ 231 | private function parseResponseStatus(array|string $response_line): array 232 | { 233 | if (is_array($response_line)) { 234 | $response_line = $response_line[count($response_line) - 1]; 235 | } 236 | $parts = explode(separator: ' ', string: $response_line, limit: 3); 237 | return [ 238 | 'protocol' => $parts[0], 239 | 'code' => $parts[1], 240 | 'message' => !empty($parts[2]) ? $parts[2] : null, 241 | ]; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | // asignar zona horaria de PHP 25 | date_default_timezone_set('America/Santiago'); 26 | 27 | // dependencias de composer 28 | require_once __DIR__ . '/../vendor/autoload.php'; 29 | 30 | // cargar variables de entorno (según si test.env existe o no). 31 | if (file_exists(__DIR__ . '/test.env')) { 32 | $dotenv = \Dotenv\Dotenv::createMutable(__DIR__, 'test.env'); 33 | try { 34 | $dotenv->load(); 35 | } catch (\Dotenv\Exception\InvalidPathException $e) { 36 | die($e->getMessage()); 37 | } catch (\Dotenv\Exception\InvalidFileException $e) { 38 | die($e->getMessage()); 39 | } 40 | } 41 | 42 | /** 43 | * Función que carga una variable de entorno o su valor por defecto 44 | * @param string varname Variable que se desea consultar 45 | * @param mixed|null default Valor por defecto de la variable 46 | */ 47 | function env(string $varname, mixed $default = null) 48 | { 49 | if (isset($_ENV[$varname])) { 50 | return $_ENV[$varname]; 51 | } 52 | $value = getenv($varname); 53 | if ($value !== false) { 54 | return $value; 55 | } 56 | return $default; 57 | } 58 | -------------------------------------------------------------------------------- /tests/dte_facturacion/AbstractDteFacturacion.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | namespace libredte\dte_facturacion; 25 | 26 | use libredte\api_client\ApiClient; 27 | use libredte\api_client\ApiException; 28 | use PHPUnit\Framework\TestCase; 29 | 30 | abstract class AbstractDteFacturacion extends TestCase 31 | { 32 | /** 33 | * Variable para desplegar resultados. 34 | * 35 | * @var bool 36 | */ 37 | protected static $verbose; 38 | 39 | /** 40 | * Variable instancia del API Client. 41 | * 42 | * @var ApiClient 43 | */ 44 | protected static $client; 45 | 46 | /** 47 | * RUT del emisor a utilizar. 48 | * 49 | * @var int 50 | */ 51 | protected static $emisor_rut; 52 | 53 | /** 54 | * Datos para producir el DTE temporal. 55 | * 56 | * @var array 57 | */ 58 | private static $datos = [ 59 | 'Encabezado' => [ 60 | 'IdDoc' => [ 61 | 'TipoDTE' => 33, 62 | ], 63 | 'Emisor' => [ 64 | 'RUTEmisor' => null, // se reemplaza al preparar la clase 65 | ], 66 | 'Receptor' => [ 67 | 'RUTRecep' => '60803000-K', 68 | 'RznSocRecep' => 'Servicio de Impuestos Internos (SII)', 69 | 'GiroRecep' => 'Administración Pública', 70 | 'Contacto' => '+56 2 3252 5575', 71 | 'CorreoRecep' => 'facturacionmipyme@sii.cl', 72 | 'DirRecep' => 'Teatinos 120', 73 | 'CmnaRecep' => 'Santiago', 74 | ], 75 | ], 76 | 'Detalle' => [ 77 | [ 78 | //'IndExe' => 1, // para items exentos 79 | 'NmbItem' => 'Asesoría de LibreDTE', 80 | 'QtyItem' => 1, 81 | 'PrcItem' => 1000, 82 | ], 83 | ], 84 | 'Referencia' => [ 85 | [ 86 | 'TpoDocRef' => 801, 87 | 'FolioRef' => 'OC123', 88 | 'FchRef' => '2015-10-01', 89 | ], 90 | ], 91 | ]; 92 | 93 | /** 94 | * Inicialización de variables y clases pre ejecución de tests. 95 | * 96 | * @return void 97 | */ 98 | public static function setUpBeforeClass(): void 99 | { 100 | self::$verbose = (bool)env(varname: 'TEST_VERBOSE', default: 'false'); 101 | self::$emisor_rut = ( 102 | explode( 103 | '-', 104 | (string)env('LIBREDTE_RUT') 105 | )[0] 106 | ); 107 | self::$datos['Encabezado']['Emisor']['RUTEmisor'] = env( 108 | 'LIBREDTE_RUT' 109 | ); 110 | self::$client = new ApiClient(); 111 | } 112 | 113 | /** 114 | * Método para listar DTEs temporales. 115 | * 116 | * @throws \libredte\api_client\ApiException 117 | * 118 | * @return array Listado de DTEs temporales entre 2015 y hoy. 119 | */ 120 | protected function listarDteTemp(): array 121 | { 122 | // Se crea el filtro a utilizar, en este caso fechas de búsqueda. 123 | $filtros = [ 124 | 'fecha_desde' => date( 125 | format: 'Y-m-d', 126 | timestamp: strtotime('-30 days') 127 | ), 128 | 'fecha_hasta' => date('Y-m-d'), 129 | ]; 130 | // Se genera el recurso a consumir. 131 | $resource = sprintf( 132 | '/dte/dte_tmps/buscar/%d', 133 | self::$emisor_rut 134 | ); 135 | // Se envía la solicitud http y se guarda su respuesta. 136 | $response = self::$client->post(resource: $resource, data: $filtros); 137 | 138 | // Si el código http no es '200', arroja error ApiException. 139 | if ($response['status']['code'] !== '200') { 140 | throw new ApiException( 141 | message: $response['body'], 142 | code: (int)$response['status']['code'] 143 | ); 144 | } 145 | 146 | // Retorna la respuesta http. 147 | return $response; 148 | } 149 | 150 | /** 151 | * Método para emitir un DTE temporal. 152 | * 153 | * @throws \libredte\api_client\ApiException 154 | * 155 | * @return array DTE temporal generado. 156 | */ 157 | protected function emitirDteTemp(): array 158 | { 159 | // Se envía la solicitud http y se guarda su respuesta. 160 | $response = self::$client->post( 161 | resource: '/dte/documentos/emitir', 162 | data: self::$datos 163 | ); 164 | 165 | // Si el código http no es '200', arroja error ApiException. 166 | if ($response['status']['code'] !== '200') { 167 | throw new ApiException( 168 | message: $response['body'], 169 | code: (int)$response['status']['code'] 170 | ); 171 | } 172 | 173 | // Retorna la respuesta http. 174 | return $response; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /tests/dte_facturacion/BuscarDteTempTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\dte_facturacion\AbstractDteFacturacion; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de pruebas que permite buscar un DTE temporal. 34 | */ 35 | class BuscarDteTempTest extends AbstractDteFacturacion 36 | { 37 | /** 38 | * Método de test que prueba el servicio para buscar un DTE temporal. 39 | * 40 | * @throws \libredte\api_client\ApiException 41 | * 42 | * @return void 43 | */ 44 | public function testBuscarDteTemp(): void 45 | { 46 | try { 47 | // Se emite un DTE temporal para ejecutar esta prueba. 48 | $dte_temp = $this->emitirDteTemp(); 49 | 50 | // Se genera el recurso para buscar el DTE temporal generado. 51 | $resource = sprintf( 52 | "/dte/dte_tmps/info/%d/%d/%s/%d", 53 | $dte_temp['body']['receptor'], 54 | $dte_temp['body']['dte'], 55 | $dte_temp['body']['codigo'], 56 | self::$emisor_rut 57 | ); 58 | 59 | // Se envía la solicitud http y se guarda su respuesta. 60 | $response = self::$client->get($resource); 61 | // Si el código http no es '200', arroja error ApiException. 62 | if ($response['status']['code'] !== '200') { 63 | throw new ApiException( 64 | message: $response['body'], 65 | code: (int)$response['status']['code'] 66 | ); 67 | } 68 | // Se obtiene el body de la lista. 69 | $documento = $response['body']; 70 | 71 | // Se compara el código con '200' Si no es 200, la prueba falla. 72 | $this->assertSame('200', $response['status']['code']); 73 | // Se despliega en consola los resultados si verbose es true. 74 | if (self::$verbose) { 75 | echo "\n",'testBuscarDteTemp() DTE: ',json_encode( 76 | $documento 77 | ),"\n"; 78 | } 79 | } catch (ApiException $e) { 80 | // Si falla, desplegará el mensaje y error en el siguiente formato: 81 | // [ApiException codigo-http] mensaje] 82 | $this->fail(sprintf( 83 | '[ApiException %d] %s', 84 | $e->getCode(), 85 | $e->getMessage() 86 | )); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tests/dte_facturacion/DescargarPdfDteTempTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\dte_facturacion\AbstractDteFacturacion; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de pruebas para descargar un PDF de un DTE temporal. 34 | */ 35 | class DescargarPdfDteTempTest extends AbstractDteFacturacion 36 | { 37 | /** 38 | * Método de test que prueba el servicio de obtener un PDF de un DTE 39 | * temporal. 40 | * 41 | * @throws \libredte\api_client\ApiException 42 | * 43 | * @return void 44 | */ 45 | public function testDescargarPdfDteTemp(): void 46 | { 47 | try { 48 | // Se emite un DTE temporal para ejecutar esta prueba. 49 | $emitir = $this->emitirDteTemp(); 50 | $documento = $emitir['body']; 51 | 52 | // Se genera el recurso a consumir. 53 | $resource = sprintf( 54 | '/dte/dte_tmps/pdf/%d/%d/%s/%d', 55 | $documento['receptor'], 56 | $documento['dte'], 57 | $documento['codigo'], 58 | self::$emisor_rut, 59 | ); 60 | // Se envía la solicitud http y se guarda su respuesta. 61 | $response = self::$client->get($resource); 62 | 63 | // Si el código http no es '200', arroja error ApiException. 64 | if ($response['status']['code'] !== '200') { 65 | throw new ApiException( 66 | message: $response['body'], 67 | code: (int)$response['status']['code'] 68 | ); 69 | } 70 | // Se compara el código con '200' Si no es 200, la prueba falla. 71 | $this->assertSame('200', $response['status']['code']); 72 | 73 | // Ruta base para el directorio actual (archivo ejecutándose en 74 | // "tests/dte_facturacion") 75 | $currentDir = __DIR__; 76 | 77 | // Nueva ruta relativa para guardar el archivo PDF en "tests/archivos" 78 | $targetDir = dirname($currentDir) . 79 | '/archivos/dte_facturacion'; 80 | 81 | // Define el nombre del archivo PDF en el nuevo directorio 82 | $filename = $targetDir . '/' . sprintf( 83 | 'LIBREDTE_%d_%d-%s.pdf', 84 | self::$emisor_rut, 85 | $documento['dte'], 86 | $documento['codigo'] 87 | ); 88 | 89 | // Verifica si el directorio existe, si no, créalo 90 | if (!is_dir($targetDir)) { 91 | mkdir(directory: $targetDir, permissions: 0777, recursive: true); 92 | } 93 | 94 | // Se genera el archivo PDF. 95 | file_put_contents($filename, $response['body']); 96 | 97 | // Se despliega en consola los resultados si verbose es true. 98 | if (self::$verbose) { 99 | echo "\n",'testDescargarPdfTemp() PDF: ',$filename,"\n"; 100 | } 101 | } catch (ApiException $e) { 102 | // Si falla, desplegará el mensaje y error en el siguiente formato: 103 | // [ApiException codigo-http] mensaje] 104 | $this->fail(sprintf( 105 | '[ApiException %d] %s', 106 | $e->getCode(), 107 | $e->getMessage() 108 | )); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /tests/dte_facturacion/EliminarDteTempTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\dte_facturacion\AbstractDteFacturacion; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de test para eliminar un DTE temporal. 34 | */ 35 | class EliminarDteTempTest extends AbstractDteFacturacion 36 | { 37 | /** 38 | * Método de test que prueba el servicio de eliminar un DTE temporal. 39 | * 40 | * @throws \libredte\api_client\ApiException 41 | * 42 | * @return void 43 | */ 44 | public function testEliminarDteTemp(): void 45 | { 46 | // Se emite un DTE temporal para ejecutar esta prueba. 47 | $dte_temp = $this->emitirDteTemp(); 48 | 49 | // Se genera el recurso a consumir. 50 | $resource = sprintf( 51 | '/dte/dte_tmps/eliminar/%d/%d/%s/%d', 52 | $dte_temp['body']['receptor'], 53 | $dte_temp['body']['dte'], 54 | $dte_temp['body']['codigo'], 55 | self::$emisor_rut 56 | ); 57 | try { 58 | // Se envía la solicitud http y se guarda su respuesta. 59 | $response = self::$client->get($resource); 60 | // Si el código http no es '200', arroja error ApiException. 61 | if ($response['status']['code'] !== '200') { 62 | throw new ApiException( 63 | message: $response['body'], 64 | code: (int)$response['status']['code'] 65 | ); 66 | } 67 | // Se compara el código con '200' Si no es 200, la prueba falla. 68 | $this->assertSame('200', $response['status']['code']); 69 | // Se despliega en consola los resultados si verbose es true. 70 | if (self::$verbose) { 71 | echo "\n",'testEliminarDteTemp() eliminar_dte ',json_encode( 72 | $response['body'] 73 | ),"\n"; 74 | } 75 | } catch (ApiException $e) { 76 | // Si falla, desplegará el mensaje y error en el siguiente formato: 77 | // [ApiException codigo-http] mensaje] 78 | $this->fail(sprintf( 79 | '[ApiException %d] %s', 80 | $e->getCode(), 81 | $e->getMessage() 82 | )); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/dte_facturacion/EmitirDteTempTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\dte_facturacion\AbstractDteFacturacion; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de tests que permite emitir un DTE Temporal. Require de método obtenido desde Dtes.php. 34 | */ 35 | class EmitirDteTempTest extends AbstractDteFacturacion 36 | { 37 | /** 38 | * Método de test que prueba el servicio emitir un DTE temporal 39 | * 40 | * @throws \libredte\api_client\ApiException 41 | * 42 | * @return void 43 | */ 44 | public function testEmitirDteTemp(): void 45 | { 46 | try { 47 | // Se emite un DTE temporal para ejecutar esta prueba. 48 | $dte_temp = $this->emitirDteTemp(); 49 | 50 | // Se compara el código con '200' Si no es 200, la prueba falla. 51 | $this->assertSame('200', $dte_temp['status']['code']); 52 | // Se despliega en consola los resultados si verbose es true. 53 | if (self::$verbose) { 54 | echo "\n",'testEmitirDteTemp() Emitir: ',json_encode( 55 | $dte_temp['body'] 56 | ),"\n"; 57 | } 58 | } catch (ApiException $e) { 59 | // Si falla, desplegará el mensaje y error en el siguiente formato: 60 | // [ApiException codigo-http] mensaje] 61 | $this->fail(sprintf( 62 | '[ApiException %d] %s', 63 | $e->getCode(), 64 | $e->getMessage() 65 | )); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/dte_facturacion/GenerarDteRealTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\dte_facturacion\AbstractDteFacturacion; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | class GenerarDteRealTest extends AbstractDteFacturacion 33 | { 34 | /** 35 | * Método de test que permite generar un DTE real a partir de 36 | * un DTE temporal. 37 | * 38 | * @throws \libredte\api_client\ApiException 39 | * 40 | * @return void 41 | */ 42 | public function testGenerarDteReal(): void 43 | { 44 | try { 45 | // Se emite un DTE temporal para ejecutar esta prueba. 46 | $dte_temp = $this->emitirDteTemp(); 47 | 48 | // Se llena una lista con la información que se va a pasar 49 | // a la petición http. 50 | $data = [ 51 | 'emisor' => self::$emisor_rut, 52 | 'receptor' => $dte_temp['body']['receptor'], 53 | 'dte' => $dte_temp['body']['dte'], 54 | 'codigo' => $dte_temp['body']['codigo'], 55 | ]; 56 | // Se envía la solicitud http y se guarda su respuesta. 57 | $response = self::$client->post( 58 | '/dte/documentos/generar', 59 | $data 60 | ); 61 | // Si el código http no es '200', arroja error ApiException. 62 | if ($response['status']['code'] !== '200') { 63 | throw new ApiException( 64 | message: $response['body'], 65 | code: (int)$response['status']['code'] 66 | ); 67 | } 68 | // Se compara el código con '200' Si no es 200, la prueba falla. 69 | $this->assertSame('200', $response['status']['code']); 70 | // Se despliega en consola los resultados si verbose es true. 71 | if (self::$verbose) { 72 | echo "\n",'testGenerarDteReal() Generar: ',json_encode( 73 | $response['body'] 74 | ),"\n"; 75 | } 76 | } catch (ApiException $e) { 77 | // Si falla, desplegará el mensaje y error en el siguiente formato: 78 | // [ApiException codigo-http] mensaje] 79 | $this->fail(sprintf( 80 | '[ApiException %d] %s', 81 | $e->getCode(), 82 | $e->getMessage() 83 | )); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/dte_facturacion/ListarDtesTempTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\dte_facturacion\AbstractDteFacturacion; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de pruebas que permite buscar un DTE temporal. 34 | */ 35 | class ListarDtesTempTest extends AbstractDteFacturacion 36 | { 37 | /** 38 | * Método de test para listar todos los DTEs temporales. 39 | * 40 | * @throws \libredte\api_client\ApiException 41 | * 42 | * @return void 43 | */ 44 | public function testListarDtesTemp(): void 45 | { 46 | try { 47 | // Se listan los DTEs temporales. 48 | $lista_dtes = $this->listarDteTemp(); 49 | 50 | // La prueba tendrá éxito si la búsqueda funciona. 51 | $this->assertTrue(true); 52 | // Se despliega en consola los resultados si verbose es true. 53 | if (self::$verbose) { 54 | echo "\n",'testListarDteTemps() Lista DTEs: ',json_encode( 55 | $lista_dtes['body'] 56 | ),"\n"; 57 | } 58 | } catch (ApiException $e) { 59 | // Si falla, desplegará el mensaje y error en el siguiente formato: 60 | // [ApiException codigo-http] mensaje] 61 | $this->fail(sprintf( 62 | '[ApiException %d] %s', 63 | $e->getCode(), 64 | $e->getMessage() 65 | )); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/lce_contabilidad/AsientoContableTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use PHPUnit\Framework\Attributes\CoversClass; 28 | use PHPUnit\Framework\TestCase; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de pruebas para probar los servicios relacionados con los 34 | * asientos contables. 35 | */ 36 | class AsientoContableTest extends TestCase 37 | { 38 | /** 39 | * Variable para desplegar resultados. 40 | * 41 | * @var bool 42 | */ 43 | protected static $verbose; 44 | 45 | /** 46 | * Variable de instanciación de API Client. 47 | * 48 | * @var ApiClient 49 | */ 50 | protected static $client; 51 | 52 | /** 53 | * RUT del emisor sin DV a utilizar. 54 | * 55 | * @var int 56 | */ 57 | protected static $emisor_rut; 58 | 59 | /** 60 | * Función para inicializar variables y clases pre ejecución de tests. 61 | * 62 | * @return void 63 | */ 64 | public static function setUpBeforeClass(): void 65 | { 66 | self::$verbose = env(varname: 'TEST_VERBOSE', default: false); 67 | self::$emisor_rut = (int)( 68 | explode( 69 | '-', 70 | (string)env('LIBREDTE_RUT') 71 | )[0] 72 | ); 73 | self::$client = new ApiClient(); 74 | } 75 | 76 | /** 77 | * Método privado para obtener datos de un asiento contable. 78 | * 79 | * Este es un ejemplo de una venta, puede ser cualquier tipo de 80 | * asiento contable las cuentas contables usadas deben existir 81 | * previamente, se asignan en las variable de entorno si no son los 82 | * códigos acá propuestos 83 | * 84 | * @return array Datos del asiento contable. 85 | */ 86 | private function _datosAsiento(): array 87 | { 88 | // Inicialización de variables de entorno. 89 | $cuenta_caja = env('TEST_LCE_CUENTA_CAJA', 1101001); 90 | $cuenta_ventas = env('TEST_LCE_CUENTA_VENTAS', 4101001); 91 | $cuenta_iva_debito = env('TEST_LCE_CUENTA_IVA_DEBITO', 2105101); 92 | 93 | // Retorna un array con los datos de un asiento contable. 94 | return [ 95 | 'fecha' => date('Y-m-d'), 96 | 'glosa' => 'Venta T33F123', 97 | 'detalle' => [ 98 | 'debe' => [ 99 | // cuenta: caja 100 | $cuenta_caja => 119, 101 | ], 102 | 'haber' => [ 103 | // cuenta: ventas 104 | $cuenta_ventas => 100, 105 | // cuenta: iva débito 106 | $cuenta_iva_debito => 19, 107 | ], 108 | ], 109 | 'operacion' => 'I', 110 | // esto es opcional, pero se recomienda ya que el SII lo puede pedir 111 | // además que permite usar un informe que indica qué documentos no 112 | // tienen asientos contables asociados (para cuadraturas) 113 | 'documentos' => ['emitidos' => [['dte' => 33, 'folio' => 123]]], 114 | ]; 115 | } 116 | 117 | /** 118 | * Método de test para crear un asiento contable. 119 | * 120 | * @throws \libredte\api_client\ApiException 121 | * 122 | * @return void 123 | */ 124 | public function testLceCrearAsiento(): void 125 | { 126 | // Recurso a consumir. 127 | $resource = sprintf( 128 | '/lce/lce_asientos/crear/%d', 129 | self::$emisor_rut 130 | ); 131 | // Creación de datos de un asiento contable 132 | $datos = $this->_datosAsiento(); 133 | try { 134 | // Se envía la solicitud http y se guarda su respuesta. 135 | $response = self::$client->post($resource, $datos); 136 | // Si el código http no es '200', arroja error ApiException. 137 | if ($response['status']['code'] != '200') { 138 | throw new ApiException( 139 | $response['body'], 140 | (int)$response['status']['code'] 141 | ); 142 | } 143 | // Se compara el código con '200' Si no es 200, la prueba falla. 144 | $this->assertSame('200', $response['status']['code']); 145 | // Se despliega en consola los resultados si verbose es true. 146 | if (self::$verbose) { 147 | echo "\n", 148 | 'test_lce_crear_asiento() asiento ', 149 | $response['body']['asiento'], 150 | "\n"; 151 | echo "\n", 152 | 'test_lce_crear_asiento() creado ', 153 | $response['body']['creado'], 154 | "\n"; 155 | } 156 | } catch (ApiException $e) { 157 | // Si falla, desplegará el mensaje y error en el siguiente formato: 158 | // [ApiException codigo-http] mensaje] 159 | $this->fail(sprintf( 160 | '[ApiException %d] %s', 161 | $e->getCode(), 162 | $e->getMessage() 163 | )); 164 | } 165 | } 166 | 167 | /** 168 | * Método privado para buscar y listar asientos contables. 169 | * 170 | * @throws \libredte\api_client\ApiException 171 | * 172 | * @return array Listado de asientos contables. 173 | */ 174 | private function _buscar(): array 175 | { 176 | // Filtros para buscar asientos contables. 177 | $filtros = [ 178 | 'fecha_desde' => date( 179 | format: 'Y-m-d', 180 | timestamp: strtotime('-30 days') 181 | ), 182 | 'fecha_hasta' => date('Y-m-d'), 183 | ]; 184 | // Recurso a consumir. 185 | $resource = sprintf( 186 | '/lce/lce_asientos/buscar/%d', 187 | self::$emisor_rut 188 | ); 189 | // Se envía la solicitud http y se guarda su respuesta. 190 | $response = self::$client->post(resource: $resource, data: $filtros); 191 | // Si el código http no es '200', arroja error ApiException. 192 | if ($response['status']['code'] != '200') { 193 | throw new ApiException( 194 | message: $response['body'], 195 | code: (int)$response['status']['code'] 196 | ); 197 | } 198 | return $response['body']; 199 | } 200 | 201 | /** 202 | * Método de test para probarla búsqueda y listado de asientos contables. 203 | * 204 | * @return void 205 | */ 206 | public function testLceBuscarAsiento(): void 207 | { 208 | try { 209 | // Búsqueda de asiento contable. 210 | $asientos = $this->_buscar(); 211 | // assertTrue si la búsqueda fue exitosa. 212 | $this->assertTrue(true); 213 | // Se despliega en consola los resultados si verbose es true. 214 | if (self::$verbose) { 215 | echo "\n",'test_lce_buscar_asientos() n_asientos ',count( 216 | $asientos 217 | ),"\n"; 218 | } 219 | } catch (ApiException $e) { 220 | // Si falla, desplegará el mensaje y error en el siguiente formato: 221 | // [ApiException codigo-http] mensaje] 222 | $this->fail(sprintf( 223 | '[ApiException %d] %s', 224 | $e->getCode(), 225 | $e->getMessage() 226 | )); 227 | } 228 | } 229 | 230 | /** 231 | * Método de test para editar un asiento contable. 232 | * 233 | * En la edición de un asiento todos los campos son opcionales, se debe 234 | * mandar a lo menos uno. Acá por simpleza se toman los mismos datos 235 | * originales ya que de esta forma el asiento que se encuentre (que no 236 | * necesariamente es el creado) se editará y "tendrá sentido" al ser igual 237 | * al creado. 238 | * 239 | * @throws \libredte\api_client\ApiException 240 | * 241 | * @return void 242 | */ 243 | public function testLceEditarAsiento(): void 244 | { 245 | $datos = $this->_datosAsiento(); 246 | $datos['glosa'] = 'VENTA CON FACTURA EDITADA'; 247 | try { 248 | // Búsqueda de asiento contable. 249 | $asientos = $this->_buscar(); 250 | // Recurso a consumir. 251 | $url = sprintf( 252 | '/lce/lce_asientos/editar/%d/%d/%d', 253 | $asientos[0]['periodo'], 254 | $asientos[0]['asiento'], 255 | self::$emisor_rut 256 | ); 257 | // Se envía la solicitud http y se guarda su respuesta. 258 | $response = self::$client->post(resource: $url, data: $datos); 259 | // Si el código http no es '200', arroja error ApiException. 260 | if ($response['status']['code'] != '200') { 261 | throw new ApiException( 262 | message: $response['body'], 263 | code: (int)$response['status']['code'] 264 | ); 265 | } 266 | // Se compara el código con '200' Si no es 200, la prueba falla. 267 | $this->assertSame('200', $response['status']['code']); 268 | // Se despliega en consola los resultados si verbose es true. 269 | if (self::$verbose) { 270 | echo "\n", 271 | 'test_lce_editar_asiento() asiento ', 272 | $response['body']['asiento'], 273 | "\n"; 274 | echo "\n", 275 | 'test_lce_editar_asiento() creado ', 276 | $response['body']['creado'], 277 | "\n"; 278 | echo "\n", 279 | 'test_lce_editar_asiento() modificado ', 280 | $response['body']['modificado'], 281 | "\n"; 282 | } 283 | } catch (ApiException $e) { 284 | // Si falla, desplegará el mensaje y error en el siguiente formato: 285 | // [ApiException codigo-http] mensaje] 286 | $this->fail(sprintf( 287 | '[ApiException %d] %s', 288 | $e->getCode(), 289 | $e->getMessage() 290 | )); 291 | } 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /tests/pagos_cobros_masivos/AbstractPagosCobrosMasivos.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | namespace libredte\pagos_cobros_masivos; 25 | 26 | use libredte\api_client\ApiClient; 27 | use libredte\api_client\ApiException; 28 | use PHPUnit\Framework\TestCase; 29 | 30 | abstract class AbstractPagosCobrosMasivos extends TestCase 31 | { 32 | /** 33 | * Variable para desplegar resultados. 34 | * 35 | * @var bool 36 | */ 37 | protected static $verbose; 38 | 39 | /** 40 | * Variable de instanciación del API Client. 41 | * 42 | * @var ApiClient 43 | */ 44 | protected static $client; 45 | 46 | /** 47 | * RUT del emisor sin DV 48 | * 49 | * @var int 50 | */ 51 | protected static $emisor_rut; 52 | 53 | /** 54 | * Función para inicializar variables y clases pre ejecución de tests. 55 | * 56 | * @return void 57 | */ 58 | public static function setUpBeforeClass(): void 59 | { 60 | self::$verbose = env(varname: 'TEST_VERBOSE', default: false); 61 | self::$emisor_rut = (int)( 62 | explode( 63 | '-', 64 | (string)env('LIBREDTE_RUT') 65 | )[0] 66 | ); 67 | self::$client = new ApiClient(); 68 | } 69 | 70 | /** 71 | * Método para buscar un cobro. 72 | * 73 | * @throws \libredte\api_client\ApiException 74 | * 75 | * @return array Arreglo que contiene el resultado de los cobros entre 76 | * 2015 y hoy. 77 | */ 78 | protected function listarCobros(): array 79 | { 80 | // Se crea la lista con filtros para aplicar a la búsqueda. 81 | $filtros = [ 82 | 'fecha_desde' => date( 83 | format: 'Y-m-d', 84 | timestamp: strtotime('-30 days') 85 | ), 86 | 'fecha_hasta' => date('Y-m-d'), 87 | 'pagado' => false, 88 | ]; 89 | // Se genera el recurso a consumir. 90 | $resource = sprintf( 91 | '/pagos/cobros/buscar/%d', 92 | self::$emisor_rut 93 | ); 94 | // Se envía la solicitud http y se guarda su respuesta. 95 | $response = self::$client->post(resource: $resource, data: $filtros); 96 | 97 | // Si el código http no es '200', arroja error ApiException. 98 | if ($response['status']['code'] != '200') { 99 | throw new ApiException( 100 | $response['body'], 101 | (int)$response['status']['code'] 102 | ); 103 | } 104 | // Si el body de la respuesta es vacío o nulo, arroja error 105 | // ApiException. 106 | if (empty($response['body'])) { 107 | throw new ApiException( 108 | message: 'No se encontraron cobros para la búsqueda realizada.', 109 | code: 404 110 | ); 111 | } 112 | return $response; 113 | } 114 | 115 | /** 116 | * Método para emitir un DTE temporal. 117 | * 118 | * @throws \libredte\api_client\ApiException 119 | * 120 | * @return array DTE temporal generado. 121 | */ 122 | private function emitirDteTemp(): array 123 | { 124 | // Datos del DTE temporal a emitir. 125 | $datos = [ 126 | 'Encabezado' => [ 127 | 'IdDoc' => [ 128 | 'TipoDTE' => 33, 129 | ], 130 | 'Emisor' => [ 131 | 'RUTEmisor' => self::$emisor_rut, 132 | ], 133 | 'Receptor' => [ 134 | 'RUTRecep' => '60803000-K', 135 | 'RznSocRecep' => 'Servicio de Impuestos Internos (SII)', 136 | 'GiroRecep' => 'Administración Pública', 137 | 'Contacto' => '+56 2 3252 5575', 138 | 'CorreoRecep' => 'facturacionmipyme@sii.cl', 139 | 'DirRecep' => 'Teatinos 120', 140 | 'CmnaRecep' => 'Santiago', 141 | ], 142 | ], 143 | 'Detalle' => [ 144 | [ 145 | //'IndExe' => 1, // para items exentos 146 | 'NmbItem' => 'Asesoría de LibreDTE', 147 | 'QtyItem' => 1, 148 | 'PrcItem' => 1000, 149 | ], 150 | ], 151 | 'Referencia' => [ 152 | [ 153 | 'TpoDocRef' => 801, 154 | 'FolioRef' => 'OC123', 155 | 'FchRef' => '2015-10-01', 156 | ], 157 | ], 158 | ]; 159 | 160 | // Se envía la solicitud http y se guarda su respuesta. 161 | $response = self::$client->post( 162 | resource: '/dte/documentos/emitir', 163 | data: $datos 164 | ); 165 | 166 | // Si el código http no es '200', arroja error ApiException. 167 | if ($response['status']['code'] !== '200') { 168 | throw new ApiException( 169 | message: $response['body'], 170 | code: (int)$response['status']['code'] 171 | ); 172 | } 173 | 174 | return $response; 175 | } 176 | 177 | /** 178 | * Método de test para obtener un cobro a partir de un DTE temporal. 179 | * 180 | * @throws \libredte\api_client\ApiException 181 | * 182 | * @return array Cobro asociado a un DTE temporal recién emitido. 183 | */ 184 | protected function obtenerCobroDteTemp(): array 185 | { 186 | // Se emite un documento temporal para obtener su cobro 187 | $documento = $this->emitirDteTemp(); 188 | 189 | // Se genera el recurso a consumir. 190 | $resource = sprintf( 191 | '/dte/dte_tmps/cobro/%d/%d/%s/%d', 192 | $documento['body']['receptor'], 193 | $documento['body']['dte'], 194 | $documento['body']['codigo'], 195 | self::$emisor_rut 196 | ); 197 | // Se envía la solicitud http y se guarda su respuesta. 198 | $response = self::$client->get($resource); 199 | // Si el código http no es '200', arroja error ApiException. 200 | if ($response['status']['code'] != '200') { 201 | throw new ApiException( 202 | message: $response['body'], 203 | code: (int)$response['status']['code'] 204 | ); 205 | } 206 | 207 | return $response; 208 | } 209 | 210 | /** 211 | * Método privado para buscar un DTE emitido. 212 | * 213 | * @throws \libredte\api_client\ApiException 214 | * 215 | * @return array Arreglo con los DTEs emitidos. 216 | */ 217 | protected function listarDteEmitidos(): array 218 | { 219 | // Filtros para la petición http. 220 | $filtros = [ 221 | 'fecha_desde' => date( 222 | format: 'Y-m-d', 223 | timestamp: strtotime('-30 days') 224 | ), 225 | 'fecha_hasta' => date('Y-m-d'), 226 | ]; 227 | // Recurso a consumir. 228 | $resource = sprintf( 229 | '/dte/dte_emitidos/buscar/%d', 230 | self::$emisor_rut 231 | ); 232 | // Se envía la solicitud http y se guarda su respuesta. 233 | $response = self::$client->post(resource: $resource, data: $filtros); 234 | // Si el código http no es '200', arroja error ApiException. 235 | if ($response['status']['code'] != '200') { 236 | throw new ApiException( 237 | message: $response['body'], 238 | code: (int)$response['status']['code'] 239 | ); 240 | } 241 | return $response; 242 | } 243 | 244 | /** 245 | * Método privado para listar cobros masivos programados. 246 | * 247 | * @throws \libredte\api_client\ApiException 248 | * 249 | * @return array Arreglo con los cobros masivos programados. 250 | */ 251 | protected function listarCobrosMasivosProgramados(): array 252 | { 253 | // Filtros para la petición http. 254 | $filtros = [ 255 | 'siguiente_desde' => date( 256 | format: 'Y-m-d', 257 | timestamp: strtotime('-30 days') 258 | ), 259 | 'siguiente_hasta' => date('Y-m-d'), 260 | 'activo' => true, 261 | ]; 262 | // Recurso a consumir. 263 | $resource = sprintf( 264 | '/pagos/cobro_masivo_programados/buscar/%d', 265 | self::$emisor_rut 266 | ); 267 | // Se envía la solicitud http y se guarda su respuesta. 268 | $response = self::$client->post(resource: $resource, data: $filtros); 269 | // Si el código http no es '200', arroja error ApiException. 270 | if ($response['status']['code'] != '200') { 271 | throw new ApiException( 272 | message: $response['body'], 273 | code: (int)$response['status']['code'] 274 | ); 275 | } 276 | // Si el body de la respuesta es vacío o nulo, arroja error ApiException. 277 | if (empty($response['body'])) { 278 | throw new ApiException( 279 | message: 'No se encontraron cobros masivos programados para la búsqueda realizada.', 280 | code: 404 281 | ); 282 | } 283 | return $response; 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /tests/pagos_cobros_masivos/BuscarCobroDteTempTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\pagos_cobros_masivos\AbstractPagosCobrosMasivos; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de pruebas para buscar un cobro asociado a un DTE temporal. 34 | */ 35 | class BuscarCobroDteTempTest extends AbstractPagosCobrosMasivos 36 | { 37 | /** 38 | * Método de test para buscar un cobro específico. 39 | * 40 | * @throws \libredte\api_client\ApiException 41 | * 42 | * @return void 43 | */ 44 | public function testBuscarCobroDteTemp(): void 45 | { 46 | try { 47 | // Se obtiene la lista de cobros. 48 | $cobro = $this->obtenerCobroDteTemp(); 49 | // Se crea el recurso a consumir. 50 | $resource = sprintf( 51 | '/pagos/cobros/info/%s/%d', 52 | $cobro['body']['codigo'], 53 | self::$emisor_rut 54 | ); 55 | // Se envía la solicitud http y se guarda su respuesta. 56 | $response = self::$client->get($resource); 57 | // Si el código http no es '200', arroja error ApiException. 58 | if ($response['status']['code'] !== '200') { 59 | throw new ApiException( 60 | message: $response['body'], 61 | code: (int)$response['status']['code'] 62 | ); 63 | } 64 | // Se compara el código con '200' Si no es 200, la prueba falla. 65 | $this->assertSame('200', $response['status']['code']); 66 | // Se despliega en consola los resultados si verbose es true. 67 | if (self::$verbose) { 68 | echo "\n",'testBuscarCobroAsociado() Cobro: ',json_encode( 69 | $response['body'] 70 | ),"\n"; 71 | } 72 | } catch (ApiException $e) { 73 | // Si falla, desplegará el mensaje y error en el siguiente formato: 74 | // [ApiException codigo-http] mensaje] 75 | $this->fail(sprintf( 76 | '[ApiException %d] %s', 77 | $e->getCode(), 78 | $e->getMessage() 79 | )); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/pagos_cobros_masivos/CrearCobroMasivoProgramadoTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\pagos_cobros_masivos\AbstractPagosCobrosMasivos; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase para ejecutar tests a los servicios de cobros masivos. 34 | */ 35 | class CrearCobroMasivoProgramadoTest extends AbstractPagosCobrosMasivos 36 | { 37 | /** 38 | * Prueba unitaria que muestra los pasos para: 39 | * - Guardar cambios en un cobro masivo programado a un receptor 40 | * 41 | * Esto permite aplicar un descuento o modificar la cantidad en el listado 42 | * de items. Por ejemplo, sirve para actualizar la cantidad de algo que se 43 | * está cobrando (ej: consumo de GB en una cuenta de hosting). 44 | * 45 | * Se puede editar todo el cobro, o sea los campos: 46 | * - dte: código del DTE, ej: 33 (factura electrónica afecta) 47 | * - dte_real: =1 emite DTE real, =0 emite cotización 48 | * - siguiente: fecha siguiente cobro AAAA-MM-DD 49 | * - activo: 1 o 0 50 | * - observacion: texto 51 | * - items: arreglo de item con campos: 52 | * - descripcion: string (máx 1000 chars) 53 | * - cantidad: real 54 | * - descuento: real 55 | * - descuento_tipo (% o $) 56 | * - referencias: arreglo de referencias con campos: 57 | * - documento 58 | * - folio 59 | * - fecha 60 | * - descripcion 61 | * 62 | * IMPORTANTE: para eliminar un item marcarlo con cantidad = 0. 63 | * No es posible eliminar vía servicios web items obligatorios. 64 | * 65 | * @throws \libredte\api_client\ApiException 66 | * 67 | * @return void 68 | */ 69 | public function testCrearCobroMasivoProgramado(): void 70 | { 71 | try { 72 | // Búsqueda de cobros masivos. 73 | $cobros = $this->listarCobrosMasivosProgramados(); 74 | // Recurso a consumir. 75 | $resource = '/pagos/cobro_masivo_programados/guardar'; 76 | // Datos del cobro masivo. 77 | $datos = [ 78 | // datos obligatorios 79 | 'emisor' => self::$emisor_rut, 80 | 'cobro_masivo_codigo' => $cobros['body'][0]['masivo_codigo'], 81 | 'receptor' => explode('-', $cobros['body'][0]['rut'])[0], 82 | // datos que varían, acá se guarda una referencia 83 | // pero podría ser modificados los items o la fecha de siguiente cobro 84 | 'referencias' => [ 85 | [ 86 | 'documento' => 801, 87 | 'folio' => 123, 88 | 'fecha' => date('Y-m-d'), // =false se elimina la referencia 89 | 'descripcion' => 'REF A OC', 90 | ], 91 | ], 92 | ]; 93 | // Se envía la solicitud http y se guarda su respuesta. 94 | $response = self::$client->post( 95 | $resource, 96 | $datos 97 | ); 98 | // Si el código http no es '200', arroja error ApiException. 99 | if ($response['status']['code'] != '200') { 100 | throw new ApiException( 101 | message: $response['body'], 102 | code: (int)$response['status']['code'] 103 | ); 104 | } 105 | // Se compara el código con '200' Si no es 200, la prueba falla. 106 | $this->assertSame('200', $response['status']['code']); 107 | // Se despliega en consola los resultados si verbose es true. 108 | if (self::$verbose) { 109 | echo "\n", 110 | 'testCrearCobroMasivoProgramado() Cobro: ', 111 | json_encode( 112 | $response['body'] 113 | ),"\n"; 114 | } 115 | } catch (ApiException $e) { 116 | // Si falla, desplegará el mensaje y error en el siguiente formato: 117 | // [ApiException codigo-http] mensaje] 118 | $this->fail(sprintf( 119 | '[ApiException %d] %s', 120 | $e->getCode(), 121 | $e->getMessage() 122 | )); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /tests/pagos_cobros_masivos/EmitirCobroMasivoProgramadoTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\pagos_cobros_masivos\AbstractPagosCobrosMasivos; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase para ejecutar tests a los servicios de cobros masivos. 34 | */ 35 | class EmitirCobroMasivoProgramadoTest extends AbstractPagosCobrosMasivos 36 | { 37 | /** 38 | * Prueba unitaria que muestra los pasos para: 39 | * - Emitir un cobro masivo, emitiendo y enviando por correo, cada uno de 40 | * los documentos generados (si así está configurado) 41 | * 42 | * @throws \libredte\api_client\ApiException 43 | * 44 | * @return void 45 | */ 46 | public function testEmitirCobroMasivoProgramado(): void 47 | { 48 | try { 49 | // Búsqueda de cobros masivos programados. 50 | $cobros = $this->listarCobrosMasivosProgramados(); 51 | // Recurso a consumir. 52 | $resource = sprintf( 53 | '/pagos/cobro_masivo_programados/emitir/%s/%d/%d', 54 | $cobros['body'][0]['masivo_codigo'], 55 | explode('-', $cobros['body'][0]['rut'])[0], 56 | self::$emisor_rut 57 | ); 58 | // Se envía la solicitud http y se guarda su respuesta. 59 | $response = self::$client->get($resource); 60 | // Si el código http no es '200', arroja error ApiException. 61 | if ($response['status']['code'] != '200') { 62 | throw new ApiException( 63 | message: $response['body'], 64 | code: (int)$response['status']['code'] 65 | ); 66 | } 67 | // Se compara el código con '200' Si no es 200, la prueba falla. 68 | $this->assertSame('200', $response['status']['code']); 69 | // Se despliega en consola los resultados si verbose es true. 70 | if (self::$verbose) { 71 | echo "\n", 72 | 'testEmitirCobroMasivoProgramado() Cobro: ', 73 | json_encode( 74 | $response['body'] 75 | ),"\n"; 76 | } 77 | } catch (ApiException $e) { 78 | // Si falla, desplegará el mensaje y error en el siguiente formato: 79 | // [ApiException codigo-http] mensaje] 80 | $this->fail(sprintf( 81 | '[ApiException %d] %s', 82 | $e->getCode(), 83 | $e->getMessage() 84 | )); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tests/pagos_cobros_masivos/ListarCobrosDteTempTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\pagos_cobros_masivos\AbstractPagosCobrosMasivos; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de pruebas para ejecutar tests de listado de cobros. 34 | */ 35 | class ListarCobrosDteTempTest extends AbstractPagosCobrosMasivos 36 | { 37 | /** 38 | * Método de test para listar los cobros existentes. 39 | * 40 | * @return void 41 | */ 42 | public function testListarCobrosDteTemp(): void 43 | { 44 | try { 45 | // Se obtiene un listado de cobros. 46 | $cobros = $this->listarCobros(); 47 | // La prueba tendrá éxito si la búsqueda funciona. 48 | $this->assertTrue(true); 49 | // Se despliega en consola los resultados si verbose es true. 50 | if (self::$verbose) { 51 | echo "\n", 52 | 'testListarCobrosDteTemp() Cobro: ', 53 | json_encode( 54 | $cobros['body'] 55 | ),"\n"; 56 | } 57 | } catch (ApiException $e) { 58 | // Si falla, desplegará el mensaje y error en el siguiente formato: 59 | // [ApiException codigo-http] mensaje] 60 | $this->fail(sprintf( 61 | '[ApiException %d] %s', 62 | $e->getCode(), 63 | $e->getMessage() 64 | )); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/pagos_cobros_masivos/ListarCobrosMasivosProgramadosTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\pagos_cobros_masivos\AbstractPagosCobrosMasivos; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de pruebas para listar cobros masivos programados. 34 | */ 35 | class ListarCobrosMasivosProgramadosTest extends AbstractPagosCobrosMasivos 36 | { 37 | /** 38 | * Método de test para listar cobros masivos programados. 39 | * 40 | * @return void 41 | */ 42 | public function testListarCobrosMasivosProgramados(): void 43 | { 44 | try { 45 | // Se listan cobros masivos programados. 46 | $cobros = $this->listarCobrosMasivosProgramados(); 47 | // La prueba tendrá éxito si la búsqueda funciona. 48 | $this->assertTrue(true); 49 | // Se despliega en consola los resultados si verbose es true. 50 | if (self::$verbose) { 51 | echo "\n", 52 | 'testListarCobroMasivoProgramado() Cobro Masivo: ', 53 | json_encode( 54 | $cobros['body'] 55 | ),"\n"; 56 | } 57 | } catch (ApiException $e) { 58 | // Si falla, desplegará el mensaje y error en el siguiente formato: 59 | // [ApiException codigo-http] mensaje] 60 | $this->fail(sprintf( 61 | '[ApiException %d] %s', 62 | $e->getCode(), 63 | $e->getMessage() 64 | )); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/pagos_cobros_masivos/ObtenerCobroDocumentoEmitidoTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\pagos_cobros_masivos\AbstractPagosCobrosMasivos; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de test para generar un cobro de un documento emitido (real). 34 | */ 35 | class ObtenerCobroDocumentoEmitidoTest extends AbstractPagosCobrosMasivos 36 | { 37 | /** 38 | * Método de test para obtener un cobro asociado a un DTE emitido. 39 | * 40 | * @throws \libredte\api_client\ApiException 41 | * 42 | * @return void 43 | */ 44 | public function testObtenerCobroDteEmitido(): void 45 | { 46 | try { 47 | // Búsqueda de DTE emitido. 48 | $documentos = $this->listarDteEmitidos(); 49 | // Recurso a consumir. 50 | $resource = sprintf( 51 | '/dte/dte_emitidos/cobro/%d/%d/%d', 52 | $documentos['body'][0]['dte'], 53 | $documentos['body'][0]['folio'], 54 | self::$emisor_rut 55 | ); 56 | // Se envía la solicitud http y se guarda su respuesta. 57 | // Se obtiene el cobro asociado con el recurso previo. 58 | $response = self::$client->get($resource); 59 | // Si el código http no es '200', arroja error ApiException. 60 | if ($response['status']['code'] != '200') { 61 | throw new ApiException( 62 | message: $response['body'], 63 | code: (int)$response['status']['code'] 64 | ); 65 | } 66 | // Se compara el código con '200' Si no es 200, la prueba falla. 67 | $this->assertSame('200', $response['status']['code']); 68 | // Se despliega en consola los resultados si verbose es true. 69 | if (self::$verbose) { 70 | echo "\n", 71 | 'testObtenerCobroDteEmitido() Cobro: ', 72 | json_encode( 73 | $response['body'] 74 | ),"\n"; 75 | } 76 | } catch (ApiException $e) { 77 | // Si falla, desplegará el mensaje y error en el siguiente formato: 78 | // [ApiException codigo-http] mensaje] 79 | $this->fail(sprintf( 80 | '[ApiException %d] %s', 81 | $e->getCode(), 82 | $e->getMessage() 83 | )); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/pagos_cobros_masivos/PagarCobroDteTempTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * Este programa es software libre: usted puede redistribuirlo y/o modificarlo 10 | * bajo los términos de la GNU Lesser General Public License (LGPL) publicada 11 | * por la Fundación para el Software Libre, ya sea la versión 3 de la Licencia, 12 | * o (a su elección) cualquier versión posterior de la misma. 13 | * 14 | * Este programa se distribuye con la esperanza de que sea útil, pero SIN 15 | * GARANTÍA ALGUNA; ni siquiera la garantía implícita MERCANTIL o de APTITUD 16 | * PARA UN PROPÓSITO DETERMINADO. Consulte los detalles de la GNU Lesser General 17 | * Public License (LGPL) para obtener una información más detallada. 18 | * 19 | * Debería haber recibido una copia de la GNU Lesser General Public License 20 | * (LGPL) junto a este programa. En caso contrario, consulte 21 | * . 22 | */ 23 | 24 | use libredte\api_client\ApiClient; 25 | use libredte\api_client\ApiException; 26 | use libredte\api_client\HttpCurlClient; 27 | use libredte\pagos_cobros_masivos\AbstractPagosCobrosMasivos; 28 | use PHPUnit\Framework\Attributes\CoversClass; 29 | 30 | #[CoversClass(ApiClient::class)] 31 | #[CoversClass(HttpCurlClient::class)] 32 | /** 33 | * Clase de pruebbas para pagar el cobro de un DTE temporal. 34 | */ 35 | class PagarCobroDteTempTest extends AbstractPagosCobrosMasivos 36 | { 37 | /** 38 | * Método de test que permite pagar un cobro de un DTE temporal. 39 | * 40 | * @throws \libredte\api_client\ApiException 41 | * 42 | * @return void 43 | */ 44 | public function testPagarCobroDteTemp(): void 45 | { 46 | try { 47 | // Se obtiene una lista de cobros. 48 | $cobro = $this->obtenerCobroDteTemp(); 49 | 50 | // Se crea el recurso a consumir. 51 | $resource = sprintf( 52 | '/pagos/cobros/pagar/%s/%d', 53 | $cobro['body']['codigo'], 54 | self::$emisor_rut 55 | ); 56 | // Se crea el array con los datos a enviar, 57 | $data = [ 58 | 'medio' => 'efectivo', 59 | 'fecha' => (string)date('Y-m-d'), 60 | ]; 61 | 62 | // Se envía la solicitud http y se guarda su respuesta. 63 | $response = self::$client->post( 64 | resource: $resource, 65 | data: $data 66 | ); 67 | 68 | // Si el código http no es '200', arroja error ApiException. 69 | if ($response['status']['code'] !== '200') { 70 | throw new ApiException( 71 | message: $response['body'], 72 | code: (int)$response['status']['code'] 73 | ); 74 | } 75 | 76 | $this->assertSame('200', $response['status']['code']); 77 | 78 | // Se despliega en consola los resultados si verbose es true. 79 | if (self::$verbose) { 80 | echo "\n", 81 | 'testPagarCobroDteTemp() Cobro: ', 82 | json_encode( 83 | $response['body'] 84 | ),"\n"; 85 | } 86 | } catch (ApiException $e) { 87 | // Si falla, desplegará el mensaje y error en el siguiente formato: 88 | // [ApiException codigo-http] mensaje] 89 | $this->fail(sprintf( 90 | '[ApiException %d] %s', 91 | $e->getCode(), 92 | $e->getMessage() 93 | )); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /tests/test.env-dist: -------------------------------------------------------------------------------- 1 | # 2 | # Variables de entorno para la ejecución de los tests 3 | # 4 | 5 | # Autenticación en LibreDTE 6 | LIBREDTE_URL="https://libredte.cl" 7 | LIBREDTE_HASH="" 8 | 9 | # Contribuyente con el que se trabajará 10 | LIBREDTE_RUT="" 11 | 12 | # Correo electrónico para las pruebas de envío 13 | TEST_EMAIL="" 14 | --------------------------------------------------------------------------------