diff --git a/README.md b/README.md
index d397baa..ea20ac1 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,3 @@
-
@@ -21,7 +20,7 @@ Dependencias
----------------
Instalación
---------
-Para poder hacer uso de nuestro SDK para consumir el servio **REST** que **SmarterWeb** le provee primero es necesario tener instalado una version de PHP ya sea la **5.6** o la version **7** y posteriormente instalar manejador de paquetes de PHP **Composer**
+Para poder hacer uso de nuestro SDK para consumir el servio **REST** que **SmarterWeb** le provee primero es necesario tener instalado una versión de PHP ya sea la **5.6** o la versión **7** y posteriormente instalar manejador de paquetes de PHP **Composer**
#### Instalar Composer #####
* Paso 1:
@@ -31,11 +30,11 @@ Dar click en **Download**
* Paso 3:
Dar clic en **Composer-Setup.exe** esto abrira una ventana en su explorador para que guarde el archivo composer
* Paso 4:
-Ejecutar el archivo descargado **Composer-Setup.exe** y seguir los pasos de instalacion
+Ejecutar el archivo descargado **Composer-Setup.exe** y seguir los pasos de instalación
#### Preparar nuestro ambiente de Desarrollo #####
* Paso 1:
-Necesitaremos crear un archivo llamador **composer.json** y dentro de el ingresaremos la libreria de la cual queremos hacer uso en nuestro ejemplo es **lunasoft/sw-sdk-php**
+Necesitaremos crear un archivo llamador **composer.json** y dentro de el ingresaremos la librería de la cual queremos hacer uso en nuestro ejemplo es **lunasoft/sw-sdk-php**
```php
{
@@ -57,10 +56,10 @@ Dentro de tu carpeta de tu proyecto abrir **CMD** o **PowerShell** y escribir lo
```
composer install
```
-De esta manera descarga las dependencias que antes escribimos dentro del require que en nuestro caso es el **SDK**
+De esta manera descarga las dependencias que antes escribimos dentro del requiere que en nuestro caso es el **SDK**
#### En caso de no usar composer ####
-Se puede hacer uso de las clases mediante la implementacion manual haciendo uso del archivo SWSDK.php en lugar del archivo vendor.php
+Se puede hacer uso de las clases mediante la implementan manual haciendo uso del archivo SWSDK.php en lugar del archivo vendor.php
```php
include('SWSDK.php');
@@ -74,7 +73,7 @@ La librería cuenta con dos servicios principales los que son la Autenticacion y
**Usuario de Pruebas:** demo
**Constraseña de Pruebas:** 123456789
#### Nueva funcionalidad para el soporte con servidores Proxy ####
-Si tu posees un servidor proxy en tu empresa y deseas que la libreria lo use, debes pasar un parametro extra llamado "proxy" con el host y puerto de tu servidor proxy.
+Si tu posees un servidor proxy en tu empresa y deseas que la librería lo use, debes pasar un parámetro extra llamado "proxy" con el host y puerto de tu servidor proxy.
```php
$params = array(
"url"=>"http://services.test.sw.com.mx",
@@ -82,7 +81,7 @@ Si tu posees un servidor proxy en tu empresa y deseas que la libreria lo use, de
);
```
## Autenticación ###
-El servicio de Autenticación es utilizado principalmente para obtener el **token** el cual sera utilizado para poder timbrar nuestro CFDI (xml) ya emitido (sellado), para poder utilizar este servicio es necesario que cuente con un **usuario** y **contraseña** para posteriormente obtenga el token, usted puede utilizar los que estan en este ejemplo para el ambiente de **Pruebas**.
+El servicio de Autenticación es utilizado principalmente para obtener el **token** el cual sera utilizado para poder timbrar nuestro CFDI (xml) ya emitido (sellado), para poder utilizar este servicio es necesario que cuente con un **usuario** y **contraseña** para posteriormente obtenga el token, usted puede utilizar los que están en este ejemplo para el ambiente de **Pruebas**.
**Obtener Token**
```php
@@ -182,7 +181,7 @@ El ejemplo anterior la respuesta es un objeto tipo **JSON** y dentro de el se en
```
## Timbrar CFDI V2 ##
-**StampV2** Recibe el contenido de un **XML** ya emitido (sellado) en formato **String**, posteriormente si la factura y el token son correctos devuelve el complemento timbre en un string (**TFD**),asi como el comprobante ya timbrado en formato string (**CFDI**), en caso contrario lanza una excepción.
+**StampV2** Recibe el contenido de un **XML** ya emitido (sellado) en formato **String**, posteriormente si la factura y el token son correctos devuelve el complemento timbre en un string (**TFD**), así como el comprobante ya timbrado en formato string (**CFDI**), en caso contrario lanza una excepción.
**Timbrar XML en formato string utilizando usuario y contraseña**
```php
@@ -283,7 +282,7 @@ El ejemplo anterior la respuesta es un objeto tipo **JSON** y dentro de el se en
```json
{"data":{
- "cfdi":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxjZmRpOkNvbXByb2JhbnRlIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3d3dy5zYXQuZ29iLm14L2NmZC8zIGh0dHA6Ly93...",
+ "cfdi":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxjZmRpOkNvbXByb2JhbnRlIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3d3dy5zYXQuZ29iLm14L2NmZC8zIGh0dHA6Ly93...",
"tfd":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxjZmRpOkNvbXByb2JhbnRlIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3d3dy5zYXQuZ29iLm14L2NmZC8zIGh0dHA6Ly93...",
"status":"success"}
```
@@ -357,7 +356,7 @@ El ejemplo anterior la respuesta es un objeto tipo **JSON** y dentro de el se en
"status":"success"}
```
**Timbrar XML en formato base64 utilizando token/credenciales**
-Si se desea, se puede usar la version 3 en la modalidad base64, esto quiere decir que se puede enviar el xml previamente sellado en formato base64, y la libreria le respondera la misma estructura de respuesta que se usa en v3 normal con el cfdi en base64 tambien.
+Si se desea, se puede usar la versión 3 en la modalidad base64, esto quiere decir que se puede enviar el xml previamente sellado en formato base64, y la librería le responderá la misma estructura de respuesta que se usa en v3 normal con el cfdi en base64 tambien.
```php
-Si se desea, se puede usar la version 4 en la modalidad base64, esto quiere decir que se puede enviar el xml previamente sellado en formato base64, y la libreria le respondera la misma estructura de respuesta que se usa en v4 normal con el cfdi en base64 tambien.
+Si se desea, se puede usar la versión 4 en la modalidad base64, esto quiere decir que se puede enviar el xml previamente sellado en formato base64, y la librería le responderá la misma estructura de respuesta que se usa en v4 normal con el cfdi en base64 también.
```php
"http://services.test.sw.com.mx",
"user"=>"demo",
@@ -952,6 +950,73 @@ En este caso se recibe un mensaje JSON, el cual contiene los siguientes datos:
}
```
+## Validación LRFC ##
+En este servicio se hace la consulta en la lista LRFC para conocer si el RFC receptor es válido y susceptible de recibir facturas.
+Ejemplo de uso
+```php
+require_once 'SWSDK.php';
+use SWServices\Validation\ValidaLrfc as ValidaLrfc;
+try {
+ $params = array("url"=>"http://services.test.sw.com.mx",
+ "user"=>"demo",
+ "password"=> "123456789"
+ );
+ ValidaLrfc::Set($params);
+ $resultadoLRFC = ValidaLrfc::ValidaLrfc('LAN8507268IA');
+ var_dump($resultadoLRFC);
+}
+catch(Exception $e){
+ echo 'Caught exception: ', $e->getMessage(), "\n";
+}
+```
+
+## Validación LCO##
+En este servicio se hace la consulta en la lista LCO conocer si el número de certificado consultado receptor se encuentra en dicha lista, y conocer los datos del mismo.
+Ejemplo de uso
+```php
+require_once 'SWSDK.php';
+use SWServices\Validation\ValidaLco as ValidaLco;
+try {
+ $params = array("url"=>"http://services.test.sw.com.mx",
+ "user"=>"demo",
+ "password"=> "123456789"
+ );
+ ValidaLco::Set($params);
+ $resultadoLCO = ValidaLco::ValidaLco('20001000000300022816');
+ var_dump($resultadoLCO);
+}
+catch(Exception $e){
+ echo 'Caught exception: ', $e->getMessage(), "\n";
+}
+```
+
+## Validación XML##
+En este servicio se hace la validación del CFDI 3.3, validando los siguientes criterios:
+
+- Integridad.
+- Sello.
+- Errores de estructura.
+- Matriz de errores del SAT (incluye complementos).
+- Estatus de la factura en el SAT (en caso de incluir TFD).
+
+Ejemplo de uso
+```php
+require_once 'SWSDK.php';
+use SWServices\Validation\ValidarXML as ValidarXML;
+try {
+ $params = array("url"=>"http://services.test.sw.com.mx",
+ "user"=>"demo",
+ "password"=> "123456789"
+ );
+ ValidarXML::Set($params);
+ $resultadoValida = ValidarXML::ValidaXML($xml); // $xml es el string del cfdi
+ var_dump($resultadoValida);
+}
+catch(Exception $e){
+ echo 'Caught exception: ', $e->getMessage(), "\n";
+}
+```
+
## Consulta Status SAT ##
**Consulta Status SAT** Recibe los parámetros de ***URL Soap***, ***RFC Emisor***, ***RFC Receptor***, ***Total***, y ***UUID*** en formato **String**, posteriormente hace la consulta en el SOAP proporcionado sobre el estatus de la factura.
diff --git a/SWSDK.php b/SWSDK.php
index dafecb5..280f4d1 100644
--- a/SWSDK.php
+++ b/SWSDK.php
@@ -5,6 +5,7 @@
require_once dirname(__FILE__) . '/SWServices/Authentication/AuthRequest.php';
require_once dirname(__FILE__) . '/SWServices/Stamp/StampRequest.php';
require_once dirname(__FILE__) . '/SWServices/Stamp/StampService.php';
+ require_once dirname(__FILE__) . '/SWServices/Stamp/StampServiceCached.php';
require_once dirname(__FILE__) . '/SWServices/Issuer/IssuerService.php';
require_once dirname(__FILE__) . '/SWServices/Cancelation/CancelationService.php';
require_once dirname(__FILE__) . '/SWServices/Cancelation/CancelationRequest.php';
diff --git a/SWServices/Cancelation/CancelationService.php b/SWServices/Cancelation/CancelationService.php
index 93e34ac..432cf6a 100644
--- a/SWServices/Cancelation/CancelationService.php
+++ b/SWServices/Cancelation/CancelationService.php
@@ -7,9 +7,16 @@
use Exception;
class CancelationService extends Services {
+ private static $_cfdiData = null;
+ private static $_xml = null;
public function __construct($params) {
parent::__construct($params);
+ $c = count($params);
+ if($c == 7 || $c == 8)
+ self::setCSD($params);
+ else if (($c == 3 || $c == 4) && isset($params['xml']))
+ self::setXml($params);
}
public static function Set($params){
@@ -67,6 +74,34 @@ public static function ConsultarCFDIRelacionadosPFX($rfc, $pfxB64, $password, $u
public static function ConsultarCFDIRelacionadosXML($xml){
return cancelationRequest::sendReqXML(Services::get_url(), Services::get_token(), $xml, Services::get_proxy(), '/relations/xml');
}
+
+ public static function CancelationByCSDParams() {
+ return cancelationRequest::sendReqCSD(Services::get_url(), Services::get_token(), self::$_cfdiData["rfc"], cancelationHandler::uuidReq(self::$_cfdiData["uuid"]), self::$_cfdiData["b64Cer"], self::$_cfdiData["b64Key"], self::$_cfdiData["password"], Services::get_proxy(), '/cfdi33/cancel/csd');
+ }
+ public static function CancelationByXMLParams() {
+ return cancelationRequest::sendReqXML(Services::get_url(), Services::get_token(), self::$_xml, Services::get_proxy(), '/cfdi33/cancel/xml');
+ }
+
+ private static function setCSD($params) {
+ if(isset($params['url']) && isset($params['token']) && isset($params['uuid']) && isset($params['password']) && isset($params['rfc']) && isset($params['b64Cer']) && isset($params['b64Key'])) {
+ self::$_cfdiData = [
+ 'uuid'=> $params['uuid'],
+ 'password'=> $params['password'],
+ 'rfc'=> $params['rfc'],
+ 'b64Cer'=> $params['b64Cer'],
+ 'b64Key'=> $params['b64Key']
+ ];
+ } else {
+ throw new Exception('Parámetros incompletos. Debe especificarse uuid, password, rfc, b64Cer, b64Key');
+ }
+ }
+ private static function setXml($params) {
+ if(isset($params['url']) && isset($params['token']) && isset($params['xml'])) {
+ self::$_xml = $params['xml'];
+ } else {
+ throw new Exception('Parámetros incompletos. Debe especificarse url, token, y archivo xml');
+ }
+ }
}
?>
\ No newline at end of file
diff --git a/SWServices/Services.php b/SWServices/Services.php
index de34a29..c3df48b 100644
--- a/SWServices/Services.php
+++ b/SWServices/Services.php
@@ -35,7 +35,7 @@ public function __construct($params) {
self::$_token = $params['token'];
date_default_timezone_set("America/Mexico_City");
self::$_expirationDate = new \DateTime('NOW');
- self::$_expirationDate->add(new \DateInterval("PT5Y"));
+ self::$_expirationDate->add(new \DateInterval("P5Y"));
}
}
diff --git a/SWServices/Stamp/StampService.php b/SWServices/Stamp/StampService.php
index 0a3fac1..2f7026c 100644
--- a/SWServices/Stamp/StampService.php
+++ b/SWServices/Stamp/StampService.php
@@ -1,15 +1,19 @@
getMessage());
+ }
+ }
+ public static function StampV2($xml, $isb64 = false, $ttl = 600){
+ try{
+ $sello = sha1(self::getSignXml($xml));
+ if(apc_add($sello, sha1($xml), $ttl)){
+ $response = stampRequest::sendReq(Services::get_url(), Services::get_token(), $xml, "v2", $isb64, Services::get_proxy(), '/cfdi33/stamp/');
+ return $response;
+ }
+ else{
+ return self::showError($ttl, apc_fetch($sello));
+ }
+ }
+ catch(Exeption $ex){
+ throw new Exception("Exception: ".$ex->getMessage());
+ }
+ }
+ public static function StampV3($xml, $isb64 = false, $ttl = 600){
+ try{
+ $sello = sha1(self::getSignXml($xml));
+ if(apc_add($sello, sha1($xml), $ttl)){
+ $response = stampRequest::sendReq(Services::get_url(), Services::get_token(), $xml, "v3", $isb64, Services::get_proxy(), '/cfdi33/stamp/');
+ return $response;
+ }
+ else{
+ return self::showError($ttl, apc_fetch($sello));
+ }
+ }
+ catch(Exeption $ex){
+ throw new Exception("Exception: ".$ex->getMessage());
+ }
+ }
+ public static function StampV4($xml, $isb64 = false, $ttl = 600){
+ try{
+ $sello = sha1(self::getSignXml($xml));
+ if(apc_add($sello, sha1($xml), $ttl)){
+ $response = stampRequest::sendReq(Services::get_url(), Services::get_token(), $xml, "v4", $isb64, Services::get_proxy(), '/cfdi33/stamp/');
+ return $response;
+ }
+ else{
+ return self::showError($ttl, apc_fetch($sello));
+ }
+ }
+ catch(Exeption $ex){
+ throw new Exception("Exception: ".$ex->getMessage());
+ }
+ }
+
+ public static function StampVersion2V1($xml, $isb64 = false, $ttl = 600){
+ try{
+ $sello = sha1(self::getSignXml($xml));
+ if(apc_add($sello, sha1($xml), $ttl)){
+ $response = stampRequest::sendReq(Services::get_url(), Services::get_token(), $xml, "v1", $isb64, Services::get_proxy(), '/cfdi33/v2/stamp/');
+ return $response;
+ }
+ else{
+ return self::showError($ttl, apc_fetch($sello));
+ }
+ }
+ catch(Exeption $ex){
+ throw new Exception("Exception: ".$ex->getMessage());
+ }
+ }
+ public static function StampVersion2V2($xml, $isb64 = false, $ttl = 600){
+ try{
+ $sello = sha1(self::getSignXml($xml));
+ if(apc_add($sello, sha1($xml), $ttl)){
+ $response = stampRequest::sendReq(Services::get_url(), Services::get_token(), $xml, "v2", $isb64, Services::get_proxy(), '/cfdi33/v2/stamp/');
+ return $response;
+ }
+ else{
+ return self::showError($ttl, apc_fetch($sello));
+ }
+ }
+ catch(Exeption $ex){
+ throw new Exception("Exception: ".$ex->getMessage());
+ }
+ }
+ public static function StampVersion2V3($xml, $isb64 = false, $ttl = 600){
+ try{
+ $sello = sha1(self::getSignXml($xml));
+ if(apc_add($sello, sha1($xml), $ttl)){
+ $response = stampRequest::sendReq(Services::get_url(), Services::get_token(), $xml, "v3", $isb64, Services::get_proxy(), '/cfdi33/v2/stamp/');
+ return $response;
+ }
+ else{
+ return self::showError($ttl, apc_fetch($sello));
+ }
+ }
+ catch(Exeption $ex){
+ throw new Exception("Exception: ".$ex->getMessage());
+ }
+ }
+ public static function StampVersion2V4($xml, $isb64 = false, $ttl = 600){
+ try{
+ $sello = sha1(self::getSignXml($xml));
+ if(apc_add($sello, sha1($xml), $ttl)){
+ $response = stampRequest::sendReq(Services::get_url(), Services::get_token(), $xml, "v4", $isb64, Services::get_proxy(), '/cfdi33/v2/stamp/');
+ return $response;
+ }
+ else{
+ return self::showError($ttl, apc_fetch($sello));
+ }
+ }
+ catch(Exeption $ex){
+ throw new Exception("Exception: ".$ex->getMessage());
+ }
+ }
+
+ private static function getSignXml($xml){
+ $xmlA = simplexml_load_string($xml);
+ $json = json_encode($xmlA);
+ $xmlA = json_decode($json, TRUE);
+ return $xmlA["@attributes"]["Sello"];
+ }
+
+ private static function showError($ttl, $hash){
+ $error = array(
+ "message" => "Se evitó un duplicado de la factura. Verifique si la misma ya fue timbrada por alguien más.",
+ "messageDetail" => "Factura registrada en la caché hace menos de $ttl segundos por otro proceso, hash(sha1) del xml: $hash",
+ "data" => null,
+ "status" => "error"
+ );
+ return json_decode(json_encode($error));
+ }
+}
+
+?>
\ No newline at end of file