|
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
dieintroduces 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 withthrowat this point:These limitations lead to logical operators rarely being of use in current PHP code.