1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file is part of FacturaScripts |
4
|
|
|
* Copyright (C) 2021-2024 Carlos Garcia Gomez <[email protected]> |
5
|
|
|
* |
6
|
|
|
* This program is free software: you can redistribute it and/or modify |
7
|
|
|
* it under the terms of the GNU Lesser General Public License as |
8
|
|
|
* published by the Free Software Foundation, either version 3 of the |
9
|
|
|
* License, or (at your option) any later version. |
10
|
|
|
* |
11
|
|
|
* This program is distributed in the hope that it will be useful, |
12
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14
|
|
|
* GNU Lesser General Public License for more details. |
15
|
|
|
* |
16
|
|
|
* You should have received a copy of the GNU Lesser General Public License |
17
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
18
|
|
|
*/ |
19
|
|
|
|
20
|
|
|
namespace FacturaScripts\Core\Base\AjaxForms; |
21
|
|
|
|
22
|
|
|
use FacturaScripts\Core\Base\ControllerPermissions; |
23
|
|
|
use FacturaScripts\Core\Base\DataBase; |
24
|
|
|
use FacturaScripts\Core\Base\DataBase\DataBaseWhere; |
25
|
|
|
use FacturaScripts\Core\Base\Translator; |
26
|
|
|
use FacturaScripts\Core\Cache; |
27
|
|
|
use FacturaScripts\Core\Model\Base\SalesDocument; |
28
|
|
|
use FacturaScripts\Core\Model\User; |
29
|
|
|
use FacturaScripts\Core\Tools; |
30
|
|
|
use FacturaScripts\Dinamic\Model\AtributoValor; |
31
|
|
|
use FacturaScripts\Dinamic\Model\Cliente; |
32
|
|
|
use FacturaScripts\Dinamic\Model\Fabricante; |
33
|
|
|
use FacturaScripts\Dinamic\Model\Familia; |
34
|
|
|
use FacturaScripts\Dinamic\Model\RoleAccess; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Description of SalesModalHTML |
38
|
|
|
* |
39
|
|
|
* @author Carlos Garcia Gomez <[email protected]> |
40
|
|
|
*/ |
41
|
|
|
class SalesModalHTML |
42
|
|
|
{ |
43
|
|
|
/** @var string */ |
44
|
|
|
protected static $codalmacen; |
45
|
|
|
|
46
|
|
|
/** @var string */ |
47
|
|
|
protected static $codcliente; |
48
|
|
|
|
49
|
|
|
/** @var string */ |
50
|
|
|
protected static $codfabricante; |
51
|
|
|
|
52
|
|
|
/** @var string */ |
53
|
|
|
protected static $codfamilia; |
54
|
|
|
|
55
|
|
|
/** @var array */ |
56
|
|
|
protected static $idatributovalores = []; |
57
|
|
|
|
58
|
|
|
/** @var string */ |
59
|
|
|
protected static $orden; |
60
|
|
|
|
61
|
|
|
/** @var string */ |
62
|
|
|
protected static $query; |
63
|
|
|
|
64
|
|
|
/** @var bool */ |
65
|
|
|
protected static $vendido; |
66
|
|
|
|
67
|
|
|
public static function apply(SalesDocument &$model, array $formData) |
68
|
|
|
{ |
69
|
|
|
self::$codalmacen = $model->codalmacen; |
70
|
|
|
self::$codcliente = $model->codcliente; |
71
|
|
|
self::$codfabricante = $formData['fp_codfabricante'] ?? ''; |
72
|
|
|
self::$codfamilia = $formData['fp_codfamilia'] ?? ''; |
73
|
|
|
self::$orden = $formData['fp_orden'] ?? 'ref_asc'; |
74
|
|
|
self::$vendido = (bool)($formData['fp_vendido'] ?? false); |
75
|
|
|
self::$query = isset($formData['fp_query']) ? |
76
|
|
|
Tools::noHtml(mb_strtolower($formData['fp_query'], 'UTF8')) : ''; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
public static function render(SalesDocument $model, string $url, User $user, ControllerPermissions $permissions): string |
80
|
|
|
{ |
81
|
|
|
self::$codalmacen = $model->codalmacen; |
82
|
|
|
|
83
|
|
|
$i18n = new Translator(); |
|
|
|
|
84
|
|
|
return $model->editable ? static::modalClientes($i18n, $url, $user, $permissions) . static::modalProductos($i18n) : ''; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
public static function renderProductList(): string |
88
|
|
|
{ |
89
|
|
|
$tbody = ''; |
90
|
|
|
$i18n = new Translator(); |
|
|
|
|
91
|
|
|
foreach (static::getProducts() as $row) { |
92
|
|
|
$cssClass = $row['nostock'] ? 'table-info clickableRow' : ($row['disponible'] > 0 ? 'clickableRow' : 'table-warning clickableRow'); |
93
|
|
|
$description = Tools::textBreak($row['descripcion'], 120) |
94
|
|
|
. static::idatributovalor($row['idatributovalor1']) |
95
|
|
|
. static::idatributovalor($row['idatributovalor2']) |
96
|
|
|
. static::idatributovalor($row['idatributovalor3']) |
97
|
|
|
. static::idatributovalor($row['idatributovalor4']); |
98
|
|
|
$tbody .= '<tr class="' . $cssClass . '" onclick="$(\'#findProductModal\').modal(\'hide\');' |
99
|
|
|
. ' return salesFormAction(\'add-product\', \'' . $row['referencia'] . '\');">' |
100
|
|
|
. '<td><b>' . $row['referencia'] . '</b> ' . $description . '</td>' |
101
|
|
|
. '<td class="text-right">' . str_replace(' ', ' ', Tools::money($row['precio'])) . '</td>'; |
102
|
|
|
|
103
|
|
|
if (self::$vendido) { |
104
|
|
|
$tbody .= '<td class="text-right">' . str_replace(' ', ' ', Tools::money($row['ultimo_precio'])) . '</td>'; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
$tbody .= '<td class="text-right">' . $row['disponible'] . '</td>' |
108
|
|
|
. '</tr>'; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
if (empty($tbody)) { |
112
|
|
|
$tbody .= '<tr class="table-warning"><td colspan="4">' . $i18n->trans('no-data') . '</td></tr>'; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
$extraTh = self::$vendido ? |
116
|
|
|
'<th class="text-right">' . $i18n->trans('last-price-sale') . '</th>' : |
117
|
|
|
''; |
118
|
|
|
return '<table class="table table-hover mb-0">' |
119
|
|
|
. '<thead>' |
120
|
|
|
. '<tr>' |
121
|
|
|
. '<th>' . $i18n->trans('product') . '</th>' |
122
|
|
|
. '<th class="text-right">' . $i18n->trans('price') . '</th>' |
123
|
|
|
. $extraTh |
124
|
|
|
. '<th class="text-right">' . $i18n->trans('stock') . '</th>' |
125
|
|
|
. '</tr>' |
126
|
|
|
. '</thead>' |
127
|
|
|
. '<tbody>' . $tbody . '</tbody>' |
128
|
|
|
. '</table>'; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
protected static function fabricantes(Translator $i18n): string |
132
|
|
|
{ |
133
|
|
|
$fabricante = new Fabricante(); |
134
|
|
|
$options = '<option value="">' . $i18n->trans('manufacturer') . '</option>' |
135
|
|
|
. '<option value="">------</option>'; |
136
|
|
|
foreach ($fabricante->all([], ['nombre' => 'ASC'], 0, 0) as $man) { |
137
|
|
|
$options .= '<option value="' . $man->codfabricante . '">' . $man->nombre . '</option>'; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return '<select name="fp_codfabricante" class="form-control" onchange="return salesFormAction(\'find-product\', \'0\');">' |
141
|
|
|
. $options . '</select>'; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
protected static function familias(Translator $i18n): string |
145
|
|
|
{ |
146
|
|
|
$options = '<option value="">' . $i18n->trans('family') . '</option>' |
147
|
|
|
. '<option value="">------</option>'; |
148
|
|
|
|
149
|
|
|
$familia = new Familia(); |
150
|
|
|
$where = [new DataBaseWhere('madre', null, 'IS')]; |
151
|
|
|
$orderBy = ['descripcion' => 'ASC']; |
152
|
|
|
foreach ($familia->all($where, $orderBy, 0, 0) as $fam) { |
153
|
|
|
$options .= '<option value="' . $fam->codfamilia . '">' . $fam->descripcion . '</option>'; |
154
|
|
|
|
155
|
|
|
// añadimos las subfamilias de forma recursiva |
156
|
|
|
$options .= static::subfamilias($fam, $i18n); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
return '<select name="fp_codfamilia" class="form-control" onchange="return salesFormAction(\'find-product\', \'0\');">' |
160
|
|
|
. $options . '</select>'; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
protected static function getClientes(User $user, ControllerPermissions $permissions): array |
164
|
|
|
{ |
165
|
|
|
// buscamos en caché |
166
|
|
|
$cacheKey = 'model-Cliente-sales-modal-' . $user->nick; |
167
|
|
|
$clientes = Cache::get($cacheKey); |
168
|
|
|
if (is_array($clientes)) { |
169
|
|
|
return $clientes; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
// ¿El usuario tiene permiso para ver todos los clientes? |
173
|
|
|
$showAll = false; |
174
|
|
|
foreach (RoleAccess::allFromUser($user->nick, 'EditCliente') as $access) { |
175
|
|
|
if (false === $access->onlyownerdata) { |
176
|
|
|
$showAll = true; |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
// consultamos la base de datos |
181
|
|
|
$cliente = new Cliente(); |
182
|
|
|
$where = [new DataBaseWhere('fechabaja', null, 'IS')]; |
183
|
|
|
if ($permissions->onlyOwnerData && !$showAll) { |
184
|
|
|
$where[] = new DataBaseWhere('codagente', $user->codagente); |
185
|
|
|
$where[] = new DataBaseWhere('codagente', null, 'IS NOT'); |
186
|
|
|
} |
187
|
|
|
$clientes = $cliente->all($where, ['LOWER(nombre)' => 'ASC']); |
188
|
|
|
|
189
|
|
|
// guardamos en caché |
190
|
|
|
Cache::set($cacheKey, $clientes); |
191
|
|
|
|
192
|
|
|
return $clientes; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
protected static function getProducts(): array |
196
|
|
|
{ |
197
|
|
|
$dataBase = new DataBase(); |
198
|
|
|
$sql = 'SELECT v.referencia, p.descripcion, v.idatributovalor1, v.idatributovalor2, v.idatributovalor3,' |
199
|
|
|
. ' v.idatributovalor4, v.precio, COALESCE(s.disponible, 0) as disponible, p.nostock' |
200
|
|
|
. ' FROM variantes v' |
201
|
|
|
. ' LEFT JOIN productos p ON v.idproducto = p.idproducto' |
202
|
|
|
. ' LEFT JOIN stocks s ON v.referencia = s.referencia AND s.codalmacen = ' . $dataBase->var2str(self::$codalmacen) |
203
|
|
|
. ' WHERE p.sevende = true AND p.bloqueado = false'; |
204
|
|
|
|
205
|
|
|
if (self::$codfabricante) { |
206
|
|
|
$sql .= ' AND codfabricante = ' . $dataBase->var2str(self::$codfabricante); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
if (self::$codfamilia) { |
210
|
|
|
$codFamilias = [$dataBase->var2str(self::$codfamilia)]; |
211
|
|
|
|
212
|
|
|
// buscamos las subfamilias |
213
|
|
|
$familia = new Familia(); |
214
|
|
|
if ($familia->loadFromCode(self::$codfamilia)) { |
215
|
|
|
foreach ($familia->getSubfamilias() as $fam) { |
216
|
|
|
$codFamilias[] = $dataBase->var2str($fam->codfamilia); |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
$sql .= ' AND codfamilia IN (' . implode(',', $codFamilias) . ')'; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
if (self::$vendido) { |
224
|
|
|
$sql .= ' AND v.referencia IN (SELECT referencia FROM lineasfacturascli' |
225
|
|
|
. ' LEFT JOIN facturascli ON lineasfacturascli.idfactura = facturascli.idfactura' |
226
|
|
|
. ' WHERE codcliente = ' . $dataBase->var2str(self::$codcliente) . ')'; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
if (self::$query) { |
230
|
|
|
$words = explode(' ', self::$query); |
231
|
|
|
if (count($words) === 1) { |
232
|
|
|
$sql .= " AND (LOWER(v.codbarras) = " . $dataBase->var2str(self::$query) |
233
|
|
|
. " OR LOWER(v.referencia) LIKE '%" . self::$query . "%'" |
234
|
|
|
. " OR LOWER(p.descripcion) LIKE '%" . self::$query . "%')"; |
235
|
|
|
} elseif (count($words) > 1) { |
236
|
|
|
$sql .= " AND (LOWER(v.referencia) LIKE '%" . self::$query . "%' OR ("; |
237
|
|
|
foreach ($words as $wc => $word) { |
238
|
|
|
$sql .= $wc > 0 ? |
239
|
|
|
" AND LOWER(p.descripcion) LIKE '%" . $word . "%'" : |
240
|
|
|
"LOWER(p.descripcion) LIKE '%" . $word . "%'"; |
241
|
|
|
} |
242
|
|
|
$sql .= "))"; |
243
|
|
|
} |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
switch (self::$orden) { |
247
|
|
|
case 'desc_asc': |
248
|
|
|
$sql .= " ORDER BY 2 ASC"; |
249
|
|
|
break; |
250
|
|
|
|
251
|
|
|
case 'price_desc': |
252
|
|
|
$sql .= " ORDER BY 7 DESC"; |
253
|
|
|
break; |
254
|
|
|
|
255
|
|
|
case 'ref_asc': |
256
|
|
|
$sql .= " ORDER BY 1 ASC"; |
257
|
|
|
break; |
258
|
|
|
|
259
|
|
|
case 'stock_desc': |
260
|
|
|
$sql .= " ORDER BY 8 DESC"; |
261
|
|
|
break; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
$results = $dataBase->selectLimit($sql); |
265
|
|
|
if (self::$vendido) { |
266
|
|
|
static::setProductsLastPrice($dataBase, $results); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
return $results; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
protected static function idatributovalor(?int $id): string |
273
|
|
|
{ |
274
|
|
|
if (empty($id)) { |
275
|
|
|
return ''; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
if (!isset(self::$idatributovalores[$id])) { |
279
|
|
|
$attValor = new AtributoValor(); |
280
|
|
|
$attValor->loadFromCode($id); |
281
|
|
|
self::$idatributovalores[$id] = $attValor->descripcion; |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
return ', ' . self::$idatributovalores[$id]; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
protected static function modalClientes(Translator $i18n, string $url, User $user, ControllerPermissions $permissions): string |
288
|
|
|
{ |
289
|
|
|
$trs = ''; |
290
|
|
|
|
291
|
|
|
|
292
|
|
|
foreach (static::getClientes($user, $permissions) as $cli) { |
293
|
|
|
$name = ($cli->nombre === $cli->razonsocial) ? $cli->nombre : $cli->nombre . ' <small>(' . $cli->razonsocial . ')</span>'; |
294
|
|
|
$trs .= '<tr class="clickableRow" onclick="document.forms[\'salesForm\'][\'codcliente\'].value = \'' |
295
|
|
|
. $cli->codcliente . '\'; $(\'#findCustomerModal\').modal(\'hide\'); salesFormAction(\'set-customer\', \'0\'); return false;">' |
296
|
|
|
. '<td><i class="fas fa-user fa-fw"></i> ' . $name . '</td>' |
297
|
|
|
. '</tr>'; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
$linkAgent = ''; |
301
|
|
|
if ($user->codagente) { |
302
|
|
|
$linkAgent = '&codagente=' . $user->codagente; |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
return '<div class="modal" id="findCustomerModal" tabindex="-1" aria-hidden="true">' |
306
|
|
|
. '<div class="modal-dialog modal-dialog-scrollable">' |
307
|
|
|
. '<div class="modal-content">' |
308
|
|
|
. '<div class="modal-header">' |
309
|
|
|
. '<h5 class="modal-title"><i class="fas fa-users fa-fw"></i> ' . $i18n->trans('customers') . '</h5>' |
310
|
|
|
. '<button type="button" class="close" data-dismiss="modal" aria-label="Close">' |
311
|
|
|
. '<span aria-hidden="true">×</span>' |
312
|
|
|
. '</button>' |
313
|
|
|
. '</div>' |
314
|
|
|
. '<div class="modal-body p-0">' |
315
|
|
|
. '<div class="p-3">' |
316
|
|
|
. '<div class="input-group">' |
317
|
|
|
. '<input type="text" id="findCustomerInput" class="form-control" placeholder="' . $i18n->trans('search') . '" />' |
318
|
|
|
. '<div class="input-group-apend">' |
319
|
|
|
. '<button type="button" class="btn btn-primary"><i class="fas fa-search"></i></button>' |
320
|
|
|
. '</div>' |
321
|
|
|
. '</div>' |
322
|
|
|
. '</div>' |
323
|
|
|
. '<table class="table table-hover mb-0">' . $trs . '</table></div>' |
324
|
|
|
. '<div class="modal-footer bg-light">' |
325
|
|
|
. '<a href="EditCliente?return=' . urlencode($url) . $linkAgent . '" class="btn btn-block btn-success">' |
326
|
|
|
. '<i class="fas fa-plus fa-fw"></i> ' . $i18n->trans('new') |
327
|
|
|
. '</a>' |
328
|
|
|
. '</div>' |
329
|
|
|
. '</div>' |
330
|
|
|
. '</div>' |
331
|
|
|
. '</div>'; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
protected static function modalProductos(Translator $i18n): string |
335
|
|
|
{ |
336
|
|
|
return '<div class="modal" id="findProductModal" tabindex="-1" aria-hidden="true">' |
337
|
|
|
. '<div class="modal-dialog modal-xl">' |
338
|
|
|
. '<div class="modal-content">' |
339
|
|
|
. '<div class="modal-header">' |
340
|
|
|
. '<h5 class="modal-title"><i class="fas fa-cubes fa-fw"></i> ' . $i18n->trans('products') . '</h5>' |
341
|
|
|
. '<button type="button" class="close" data-dismiss="modal" aria-label="Close">' |
342
|
|
|
. '<span aria-hidden="true">×</span>' |
343
|
|
|
. '</button>' |
344
|
|
|
. '</div>' |
345
|
|
|
. '<div class="modal-body">' |
346
|
|
|
. '<div class="form-row">' |
347
|
|
|
. '<div class="col-sm mb-2">' |
348
|
|
|
. '<div class="input-group">' |
349
|
|
|
. '<input type="text" name="fp_query" class="form-control" id="productModalInput" placeholder="' . $i18n->trans('search') |
350
|
|
|
. '" onkeyup="return salesFormActionWait(\'find-product\', \'0\', event);"/>' |
351
|
|
|
. '<div class="input-group-append">' |
352
|
|
|
. '<button class="btn btn-primary btn-spin-action" type="button" onclick="return salesFormAction(\'find-product\', \'0\');">' |
353
|
|
|
. '<i class="fas fa-search"></i></button>' |
354
|
|
|
. '</div>' |
355
|
|
|
. '</div>' |
356
|
|
|
. '</div>' |
357
|
|
|
. '<div class="col-sm mb-2">' . static::fabricantes($i18n) . '</div>' |
358
|
|
|
. '<div class="col-sm mb-2">' . static::familias($i18n) . '</div>' |
359
|
|
|
. '<div class="col-sm mb-2">' . static::orden($i18n) . '</div>' |
360
|
|
|
. '</div>' |
361
|
|
|
. '<div class="form-row">' |
362
|
|
|
. '<div class="col-sm">' |
363
|
|
|
. '<div class="form-check">' |
364
|
|
|
. '<input type="checkbox" name="fp_vendido" value="1" class="form-check-input" id="vendido" onchange="return salesFormAction(\'find-product\', \'0\');">' |
365
|
|
|
. '<label class="form-check-label" for="vendido">' . $i18n->trans('previously-sold-to-customer') . '</label>' |
366
|
|
|
. '</div>' |
367
|
|
|
. '</div>' |
368
|
|
|
. '</div>' |
369
|
|
|
. '</div>' |
370
|
|
|
. '<div class="table-responsive" id="findProductList">' . static::renderProductList() . '</div>' |
371
|
|
|
. '</div>' |
372
|
|
|
. '</div>' |
373
|
|
|
. '</div>'; |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
protected static function orden(Translator $i18n): string |
377
|
|
|
{ |
378
|
|
|
return '<div class="input-group">' |
379
|
|
|
. '<div class="input-group-prepend"><span class="input-group-text"><i class="fas fa-sort-amount-down-alt"></i></span></div>' |
380
|
|
|
. '<select name="fp_orden" class="form-control" onchange="return salesFormAction(\'find-product\', \'0\');">' |
381
|
|
|
. '<option value="">' . $i18n->trans('sort') . '</option>' |
382
|
|
|
. '<option value="">------</option>' |
383
|
|
|
. '<option value="ref_asc">' . $i18n->trans('reference') . '</option>' |
384
|
|
|
. '<option value="desc_asc">' . $i18n->trans('description') . '</option>' |
385
|
|
|
. '<option value="price_desc">' . $i18n->trans('price') . '</option>' |
386
|
|
|
. '<option value="stock_desc">' . $i18n->trans('stock') . '</option>' |
387
|
|
|
. '</select>' |
388
|
|
|
. '</div>'; |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
protected static function setProductsLastPrice(DataBase $db, array &$items): void |
392
|
|
|
{ |
393
|
|
|
foreach ($items as $key => $item) { |
394
|
|
|
// obtenemos el último precio en facturas de este cliente |
395
|
|
|
$sql = 'SELECT pvpunitario FROM lineasfacturascli l' |
396
|
|
|
. ' LEFT JOIN facturascli f ON f.idfactura = l.idfactura' |
397
|
|
|
. ' WHERE f.codcliente = ' . $db->var2str(self::$codcliente) |
398
|
|
|
. ' AND l.referencia = ' . $db->var2str($item['referencia']) |
399
|
|
|
. ' ORDER BY f.fecha DESC'; |
400
|
|
|
foreach ($db->selectLimit($sql, 1) as $row) { |
401
|
|
|
$items[$key]['ultimo_precio'] = $row['pvpunitario']; |
402
|
|
|
continue 2; |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
// no hay facturas, asignamos el último precio de venta |
406
|
|
|
$items[$key]['ultimo_precio'] = $item['precio']; |
407
|
|
|
} |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
private static function subfamilias(Familia $family, Translator $i18n, int $level = 1): string |
411
|
|
|
{ |
412
|
|
|
$options = ''; |
413
|
|
|
foreach ($family->getSubfamilias() as $fam) { |
414
|
|
|
$options .= '<option value="' . $fam->codfamilia . '">' |
415
|
|
|
. str_repeat('-', $level) . ' ' . $fam->descripcion |
416
|
|
|
. '</option>'; |
417
|
|
|
|
418
|
|
|
// añadimos las subfamilias de forma recursiva |
419
|
|
|
$options .= static::subfamilias($fam, $i18n, $level + 1); |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
return $options; |
423
|
|
|
} |
424
|
|
|
} |
425
|
|
|
|