1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* LibreDTE |
5
|
|
|
* Copyright (C) SASCO SpA (https://sasco.cl) |
6
|
|
|
* |
7
|
|
|
* Este programa es software libre: usted puede redistribuirlo y/o |
8
|
|
|
* modificarlo bajo los términos de la Licencia Pública General Affero de GNU |
9
|
|
|
* publicada por la Fundación para el Software Libre, ya sea la versión |
10
|
|
|
* 3 de la Licencia, o (a su elección) cualquier versión posterior de la |
11
|
|
|
* misma. |
12
|
|
|
* |
13
|
|
|
* Este programa se distribuye con la esperanza de que sea útil, pero |
14
|
|
|
* SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita |
15
|
|
|
* MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO. |
16
|
|
|
* Consulte los detalles de la Licencia Pública General Affero de GNU para |
17
|
|
|
* obtener una información más detallada. |
18
|
|
|
* |
19
|
|
|
* Debería haber recibido una copia de la Licencia Pública General Affero de GNU |
20
|
|
|
* junto a este programa. |
21
|
|
|
* En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>. |
22
|
|
|
*/ |
23
|
|
|
|
24
|
|
|
namespace sasco\LibreDTE\Sii\Factoring; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Clase que representa la cesion de un documento |
28
|
|
|
* @author Adonias Vasquez (adonias.vasquez[at]epys.cl) |
29
|
|
|
* @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
30
|
|
|
* @version 2016-12-10 |
31
|
|
|
*/ |
32
|
|
|
class Aec extends \sasco\LibreDTE\Sii\Base\Envio |
33
|
|
|
{ |
34
|
|
|
|
35
|
|
|
private $cedido; ///< Objeto DteCedido |
36
|
|
|
private $cesiones = []; ///< Arreglo con los objetos de cesiones (ya que se puede ceder múltiples veces el DTE) |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Método que agrega el objeto DteCedido |
40
|
|
|
* @param DteCedido Objeto de \sasco\LibreDTE\Sii\Factoring\DteCedido |
41
|
|
|
* @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
42
|
|
|
* @version 2016-12-10 |
43
|
|
|
*/ |
44
|
|
|
public function agregarDteCedido(DTECedido $Cedido) |
45
|
|
|
{ |
46
|
|
|
$this->cedido = $Cedido; |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Método que agrega el objeto Cesion |
51
|
|
|
* @param Cesion Objeto de \sasco\LibreDTE\Sii\Factoring\Cesion |
52
|
|
|
* @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
53
|
|
|
* @version 2016-12-10 |
54
|
|
|
*/ |
55
|
|
|
public function agregarCesion(Cesion $Cesion) |
56
|
|
|
{ |
57
|
|
|
$this->cesiones[] = $Cesion; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Método para asignar la carátula. Opcional, si no se usa se sacan los datos |
62
|
|
|
* del documento de Cesion |
63
|
|
|
* @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
64
|
|
|
* @version 2016-12-10 |
65
|
|
|
*/ |
66
|
|
|
public function setCaratula(array $caratula = []) |
67
|
|
|
{ |
68
|
|
|
$this->caratula = array_merge([ |
69
|
|
|
'@attributes' => [ |
70
|
|
|
'version' => '1.0' |
71
|
|
|
], |
72
|
|
|
'RutCedente' => isset($this->cesiones[0]) ? $this->cesiones[0]->getCedente()['RUT'] : false, |
73
|
|
|
'RutCesionario' => isset($this->cesiones[0]) ? $this->cesiones[0]->getCesionario()['RUT'] : false, |
74
|
|
|
'NmbContacto' => isset($this->cesiones[0]) ? $this->cesiones[0]->getCedente()['RUTAutorizado']['Nombre'] : false, |
75
|
|
|
'FonoContacto' => false, |
76
|
|
|
'MailContacto' => isset($this->cesiones[0]) ? $this->cesiones[0]->getCedente()['eMail'] : false, |
77
|
|
|
'TmstFirmaEnvio' => date('Y-m-d\TH:i:s'), |
78
|
|
|
], $caratula); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Método que genera el XML del AEC |
83
|
|
|
* @return XML AEC con DTE y Cesion |
84
|
|
|
* @author Adonias Vasquez (adonias.vasquez[at]epys.cl) |
85
|
|
|
* @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) |
86
|
|
|
* @version 2016-12-10 |
87
|
|
|
*/ |
88
|
|
|
public function generar() |
89
|
|
|
{ |
90
|
|
|
if (!isset($this->cedido) or !isset($this->cesiones[0])) |
|
|
|
|
91
|
|
|
return false; |
|
|
|
|
92
|
|
|
if (!isset($this->caratula)) |
93
|
|
|
$this->setCaratula(); |
94
|
|
|
// genear XML del envío |
95
|
|
|
$xmlEnvio = (new \sasco\LibreDTE\XML())->generate([ |
96
|
|
|
'AEC' => [ |
97
|
|
|
'@attributes' => [ |
98
|
|
|
'xmlns' => 'http://www.sii.cl/SiiDte', |
99
|
|
|
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', |
100
|
|
|
'xsi:schemaLocation' => 'http://www.sii.cl/SiiDte AEC_v10.xsd', |
101
|
|
|
'version' => '1.0' |
102
|
|
|
], |
103
|
|
|
'DocumentoAEC' => [ |
104
|
|
|
'@attributes' => [ |
105
|
|
|
'ID' => 'LibreDTE_AEC' |
106
|
|
|
], |
107
|
|
|
'Caratula' => $this->caratula, |
108
|
|
|
'Cesiones' => [ |
109
|
|
|
'DTECedido' => null, |
110
|
|
|
'Cesion' => null, |
111
|
|
|
] |
112
|
|
|
] |
113
|
|
|
] |
114
|
|
|
])->saveXML(); |
115
|
|
|
// agregar XML de DTE cedido y cesión |
116
|
|
|
$cedido_xml = trim(str_replace(['<?xml version="1.0" encoding="ISO-8859-1"?>', '<?xml version="1.0"?>'], '', $this->cedido->saveXML())); |
117
|
|
|
$cesion_xml = ''; |
118
|
|
|
foreach ($this->cesiones as $cesion) { |
119
|
|
|
$cesion_xml .= trim(str_replace(['<?xml version="1.0" encoding="ISO-8859-1"?>', '<?xml version="1.0"?>'], '', $cesion->saveXML()))."\n"; |
120
|
|
|
} |
121
|
|
|
$xmlEnvio = str_replace( |
122
|
|
|
['<DTECedido/>', '<Cesion/>'], |
123
|
|
|
[$cedido_xml, $cesion_xml], |
124
|
|
|
$xmlEnvio |
125
|
|
|
); |
126
|
|
|
// firmar XML del envío y entregar |
127
|
|
|
$this->xml_data = $this->Firma->signXML($xmlEnvio, '#LibreDTE_AEC', 'DocumentoAEC', true); |
|
|
|
|
128
|
|
|
return $this->xml_data; |
|
|
|
|
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Método que realiza el envío del AEC al SII |
133
|
|
|
* @return Track ID del envío o =false si hubo algún problema al enviar el documento |
134
|
|
|
* @author Adonias Vasquez (adonias.vasquez[at]epys.cl) |
135
|
|
|
* @version 2016-12-10 |
136
|
|
|
*/ |
137
|
|
|
public function enviar() |
138
|
|
|
{ |
139
|
|
|
// generar XML que se enviará |
140
|
|
|
if (!$this->xml_data) |
141
|
|
|
$this->xml_data = $this->generar(); |
142
|
|
View Code Duplication |
if (!$this->xml_data) { |
|
|
|
|
143
|
|
|
\sasco\LibreDTE\Log::write( |
144
|
|
|
\sasco\LibreDTE\Estado::DOCUMENTO_ERROR_GENERAR_XML, |
145
|
|
|
\sasco\LibreDTE\Estado::get( |
|
|
|
|
146
|
|
|
\sasco\LibreDTE\Estado::DOCUMENTO_ERROR_GENERAR_XML, |
147
|
|
|
substr(get_class($this), strrpos(get_class($this), '\\')+1) |
148
|
|
|
) |
149
|
|
|
); |
150
|
|
|
return false; |
151
|
|
|
} |
152
|
|
|
// validar schema del documento antes de enviar |
153
|
|
|
if (!$this->schemaValidate()) |
|
|
|
|
154
|
|
|
return false; |
155
|
|
|
// solicitar token |
156
|
|
|
$token = \sasco\LibreDTE\Sii\Autenticacion::getToken($this->Firma); |
|
|
|
|
157
|
|
|
if (!$token) |
|
|
|
|
158
|
|
|
return false; |
159
|
|
|
// enviar AEC |
160
|
|
|
$email = $this->caratula['MailContacto']; |
161
|
|
|
$emisor = $this->caratula['RutCedente']; |
162
|
|
|
$result = $this->enviarRTC($email, $emisor, $this->xml_data, $token, 10); |
|
|
|
|
163
|
|
|
if ($result===false) |
164
|
|
|
return false; |
165
|
|
|
if (!is_numeric((string)$result->TRACKID)) |
166
|
|
|
return false; |
167
|
|
|
return (int)(string)$result->TRACKID; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Método que realiza el envío de un AEC al SII |
172
|
|
|
* Referencia: https://palena.sii.cl/cgi_rtc/RTC/RTCDocum.cgi?2 |
173
|
|
|
* @param email del usuario que envía el AEC |
174
|
|
|
* @param empresa RUT de la empresa emisora del AEC |
175
|
|
|
* @param dte Documento XML con el DTE que se desea enviar a SII |
176
|
|
|
* @param token Token de autenticación automática ante el SII |
177
|
|
|
* @param retry Intentos que se realizarán como máximo para obtener respuesta |
178
|
|
|
* @return Respuesta XML desde SII o bien null si no se pudo obtener respuesta |
179
|
|
|
* @author Adonias Vasquez (adonias.vasquez[at]epys.cl) |
180
|
|
|
* @author Esteban De La Fuente Rubio (esteban[sasco.cl]) |
181
|
|
|
* @version 2017-05-11 |
182
|
|
|
*/ |
183
|
|
|
private function enviarRTC($email, $empresa, $dte, $token, $retry = null) |
184
|
|
|
{ |
185
|
|
|
// definir datos que se usarán en el envío |
186
|
|
|
list($rutCompany, $dvCompany) = explode('-', str_replace('.', '', $empresa)); |
187
|
|
|
if (strpos($dte, '<?xml') === false) { |
188
|
|
|
$dte = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . $dte; |
189
|
|
|
} |
190
|
|
View Code Duplication |
do { |
|
|
|
|
191
|
|
|
$file = sys_get_temp_dir() . '/aec_' . md5(microtime() . $token . $dte) . '.xml'; |
192
|
|
|
} while (file_exists($file)); |
193
|
|
|
file_put_contents($file, $dte); |
194
|
|
|
$data = [ |
195
|
|
|
'emailNotif' => $email, |
196
|
|
|
'rutCompany' => $rutCompany, |
197
|
|
|
'dvCompany' => $dvCompany, |
198
|
|
|
'archivo' => curl_file_create( |
199
|
|
|
$file, |
200
|
|
|
'application/xml', |
201
|
|
|
basename($file) |
202
|
|
|
), |
203
|
|
|
]; |
204
|
|
|
// crear sesión curl con sus opciones |
205
|
|
|
$curl = curl_init(); |
206
|
|
|
$header = [ |
207
|
|
|
'User-Agent: Mozilla/4.0 (compatible; PROG 1.0; LibreDTE)', |
208
|
|
|
'Referer: https://libredte.cl', |
209
|
|
|
'Cookie: TOKEN='.$token, |
210
|
|
|
]; |
211
|
|
|
$url = 'https://'.\sasco\LibreDTE\Sii::getServidor().'.sii.cl/cgi_rtc/RTC/RTCAnotEnvio.cgi'; |
212
|
|
|
curl_setopt($curl, CURLOPT_POST, true); |
213
|
|
|
curl_setopt($curl, CURLOPT_POSTFIELDS, $data); |
214
|
|
|
curl_setopt($curl, CURLOPT_HTTPHEADER, $header); |
215
|
|
|
curl_setopt($curl, CURLOPT_URL, $url); |
216
|
|
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); |
217
|
|
|
// si no se debe verificar el SSL se asigna opción a curl, además si |
218
|
|
|
// se está en el ambiente de producción y no se verifica SSL se |
219
|
|
|
// generará una entrada en el log |
220
|
|
View Code Duplication |
if (!\sasco\LibreDTE\Sii::getVerificarSSL()) { |
|
|
|
|
221
|
|
|
if (\sasco\LibreDTE\Sii::getAmbiente()==\sasco\LibreDTE\Sii::PRODUCCION) { |
222
|
|
|
\sasco\LibreDTE\Log::write( |
223
|
|
|
\sasco\LibreDTE\Estado::ENVIO_SSL_SIN_VERIFICAR, |
224
|
|
|
\sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIO_SSL_SIN_VERIFICAR), |
|
|
|
|
225
|
|
|
LOG_WARNING |
|
|
|
|
226
|
|
|
); |
227
|
|
|
} |
228
|
|
|
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); |
229
|
|
|
} |
230
|
|
|
// enviar XML al SII |
231
|
|
View Code Duplication |
for ($i = 0; $i < $retry; $i++) { |
|
|
|
|
232
|
|
|
$response = curl_exec($curl); |
233
|
|
|
if ($response and $response != 'Error 500') |
|
|
|
|
234
|
|
|
break; |
235
|
|
|
} |
236
|
|
|
unlink($file); |
237
|
|
|
// verificar respuesta del envío y entregar error en caso que haya uno |
238
|
|
|
if (!$response or $response == 'Error 500') { |
|
|
|
|
239
|
|
|
if (!$response) |
|
|
|
|
240
|
|
|
\sasco\LibreDTE\Log::write(\sasco\LibreDTE\Estado::ENVIO_ERROR_CURL, \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIO_ERROR_CURL, curl_error($curl))); |
|
|
|
|
241
|
|
|
if ($response == 'Error 500') |
242
|
|
|
\sasco\LibreDTE\Log::write(\sasco\LibreDTE\Estado::ENVIO_ERROR_500, \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIO_ERROR_500)); |
|
|
|
|
243
|
|
|
return false; |
244
|
|
|
} |
245
|
|
|
// cerrar sesión curl |
246
|
|
|
curl_close($curl); |
247
|
|
|
// crear XML con la respuesta y retornar |
248
|
|
|
try { |
249
|
|
|
$xml = new \SimpleXMLElement($response, LIBXML_COMPACT); |
250
|
|
|
} catch (Exception $e) { |
|
|
|
|
251
|
|
|
\sasco\LibreDTE\Log::write(\sasco\LibreDTE\Estado::ENVIO_ERROR_XML, \sasco\LibreDTE\Estado::get(\sasco\LibreDTE\Estado::ENVIO_ERROR_XML, $e->getMessage())); |
|
|
|
|
252
|
|
|
return false; |
253
|
|
|
} |
254
|
|
|
/* |
255
|
|
|
* 0 Envío recibido OK. |
256
|
|
|
* 1 Rut usuario autenticado no tiene permiso para enviar en empresa Cedente. |
257
|
|
|
* 2 Error en tamaño del archivo enviado. |
258
|
|
|
* 4 Faltan parámetros de entrada. |
259
|
|
|
* 5 Error de autenticación, TOKEN inválido, no existe o está expirado. |
260
|
|
|
* 6 Empresa no es DTE. |
261
|
|
|
* 9 Error Interno. |
262
|
|
|
* 10 Error Interno |
263
|
|
|
*/ |
264
|
|
|
$error = [ |
265
|
|
|
1 => 'Rut usuario autenticado no tiene permiso para enviar en empresa Cedente', |
266
|
|
|
2 => 'Error en tamaño del archivo enviado', |
267
|
|
|
4 => 'Faltan parámetros de entrada', |
268
|
|
|
5 => 'Error de autenticación, TOKEN inválido, no existe o está expirado', |
269
|
|
|
6 => 'Empresa no es DTE', |
270
|
|
|
9 => 'Error Interno', |
271
|
|
|
10 => 'Error Interno' |
272
|
|
|
]; |
273
|
|
|
if ($xml->STATUS != 0) { |
274
|
|
|
\sasco\LibreDTE\Log::write( |
275
|
|
|
$xml->STATUS, |
276
|
|
|
$error[$xml->STATUS] |
|
|
|
|
277
|
|
|
); |
278
|
|
|
} |
279
|
|
|
return $xml; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
} |
283
|
|
|
|
PHP has two types of connecting operators (logical operators, and boolean operators):
and
&&
or
||
The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like
&&
, or||
.Let’s take a look at a few examples:
Logical Operators are used for Control-Flow
One case where you explicitly want to use logical operators is for control-flow such as this:
Since
die
introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined withthrow
at this point:These limitations lead to logical operators rarely being of use in current PHP code.