1 | <?php |
||||
2 | /** |
||||
3 | * This file is part of FacturaScripts |
||||
4 | * Copyright (C) 2021-2023 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\DataBase; |
||||
23 | use FacturaScripts\Core\Base\DataBase\DataBaseWhere; |
||||
24 | use FacturaScripts\Core\Base\Translator; |
||||
25 | use FacturaScripts\Core\Model\Base\PurchaseDocument; |
||||
26 | use FacturaScripts\Core\Tools; |
||||
27 | use FacturaScripts\Dinamic\Model\AtributoValor; |
||||
28 | use FacturaScripts\Dinamic\Model\Fabricante; |
||||
29 | use FacturaScripts\Dinamic\Model\Familia; |
||||
30 | use FacturaScripts\Dinamic\Model\Proveedor; |
||||
31 | |||||
32 | /** |
||||
33 | * Description of PurchasesModalHTML |
||||
34 | * |
||||
35 | * @author Carlos Garcia Gomez <[email protected]> |
||||
36 | * @author Jose Antonio Cuello Principal <[email protected]> |
||||
37 | */ |
||||
38 | class PurchasesModalHTML |
||||
39 | { |
||||
40 | /** @var string */ |
||||
41 | protected static $codalmacen; |
||||
42 | |||||
43 | /** @var string */ |
||||
44 | protected static $coddivisa; |
||||
45 | |||||
46 | /** @var string */ |
||||
47 | protected static $codfabricante; |
||||
48 | |||||
49 | /** @var string */ |
||||
50 | protected static $codfamilia; |
||||
51 | |||||
52 | /** @var string */ |
||||
53 | protected static $codproveedor; |
||||
54 | |||||
55 | /** @var bool */ |
||||
56 | protected static $comprado; |
||||
57 | |||||
58 | /** @var array */ |
||||
59 | protected static $idatributovalores = []; |
||||
60 | |||||
61 | /** @var string */ |
||||
62 | protected static $orden; |
||||
63 | |||||
64 | /** @var string */ |
||||
65 | protected static $query; |
||||
66 | |||||
67 | public static function apply(PurchaseDocument &$model, array $formData): void |
||||
68 | { |
||||
69 | self::$codalmacen = $model->codalmacen; |
||||
70 | self::$coddivisa = $model->coddivisa; |
||||
71 | self::$codfabricante = $formData['fp_codfabricante'] ?? ''; |
||||
72 | self::$codfamilia = $formData['fp_codfamilia'] ?? ''; |
||||
73 | self::$codproveedor = $model->codproveedor; |
||||
74 | self::$orden = $formData['fp_orden'] ?? 'ref_asc'; |
||||
75 | self::$comprado = (bool)($formData['fp_comprado'] ?? false); |
||||
76 | self::$query = isset($formData['fp_query']) ? |
||||
77 | Tools::noHtml(mb_strtolower($formData['fp_query'], 'UTF8')) : ''; |
||||
78 | } |
||||
79 | |||||
80 | public static function render(PurchaseDocument $model, string $url = ''): string |
||||
81 | { |
||||
82 | self::$codalmacen = $model->codalmacen; |
||||
83 | self::$coddivisa = $model->coddivisa; |
||||
84 | self::$codproveedor = $model->codproveedor; |
||||
85 | |||||
86 | $i18n = new Translator(); |
||||
0 ignored issues
–
show
Deprecated Code
introduced
by
Loading history...
|
|||||
87 | return $model->editable ? static::modalProveedores($i18n, $url) . static::modalProductos($i18n) : ''; |
||||
88 | } |
||||
89 | |||||
90 | public static function renderProductList(): string |
||||
91 | { |
||||
92 | $tbody = ''; |
||||
93 | $i18n = new Translator(); |
||||
0 ignored issues
–
show
The class
FacturaScripts\Core\Base\Translator has been deprecated: since FacturaScripts 2023.06
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
94 | foreach (static::getProducts() as $row) { |
||||
95 | $cssClass = $row['nostock'] ? 'table-info clickableRow' : ($row['disponible'] > 0 ? 'clickableRow' : 'table-warning clickableRow'); |
||||
96 | $cost = $row['neto'] ?? $row['coste']; |
||||
97 | $label = empty($row['refproveedor']) || $row['refproveedor'] === $row['referencia'] ? |
||||
98 | '<b>' . $row['referencia'] . '</b>' : |
||||
99 | '<b>' . $row['referencia'] . '</b> <span class="badge badge-light">' . $row['refproveedor'] . '</span>'; |
||||
100 | $description = Tools::textBreak($row['descripcion'], 120) |
||||
101 | . static::idatributovalor($row['idatributovalor1']) |
||||
102 | . static::idatributovalor($row['idatributovalor2']) |
||||
103 | . static::idatributovalor($row['idatributovalor3']) |
||||
104 | . static::idatributovalor($row['idatributovalor4']); |
||||
105 | $tbody .= '<tr class="' . $cssClass . '" onclick="$(\'#findProductModal\').modal(\'hide\');' |
||||
106 | . ' return purchasesFormAction(\'add-product\', \'' . $row['referencia'] . '\');">' |
||||
107 | . '<td>' . $label . ' ' . $description . '</td>' |
||||
108 | . '<td class="text-right">' . str_replace(' ', ' ', Tools::money($cost)) . '</td>' |
||||
109 | . '<td class="text-right">' . str_replace(' ', ' ', Tools::money($row['precio'])) . '</td>' |
||||
110 | . '<td class="text-right">' . $row['disponible'] . '</td>' |
||||
111 | . '</tr>'; |
||||
112 | } |
||||
113 | |||||
114 | if (empty($tbody)) { |
||||
115 | $tbody .= '<tr class="table-warning"><td colspan="4">' . $i18n->trans('no-data') . '</td></tr>'; |
||||
116 | } |
||||
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('cost-price') . '</th>' |
||||
123 | . '<th class="text-right">' . $i18n->trans('price') . '</th>' |
||||
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 purchasesFormAction(\'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 purchasesFormAction(\'find-product\', \'0\');">' |
||||
160 | . $options . '</select>'; |
||||
161 | } |
||||
162 | |||||
163 | protected static function getProducts(): array |
||||
164 | { |
||||
165 | $dataBase = new DataBase(); |
||||
166 | $sql = 'SELECT v.referencia, pp.refproveedor, p.descripcion, v.idatributovalor1, v.idatributovalor2, v.idatributovalor3,' |
||||
167 | . ' v.idatributovalor4, v.coste, v.precio, pp.neto, COALESCE(s.disponible, 0) as disponible, p.nostock' |
||||
168 | . ' FROM variantes v' |
||||
169 | . ' LEFT JOIN productos p ON v.idproducto = p.idproducto' |
||||
170 | . ' LEFT JOIN stocks s ON v.referencia = s.referencia' |
||||
171 | . ' AND s.codalmacen = ' . $dataBase->var2str(self::$codalmacen) |
||||
172 | . ' LEFT JOIN productosprov pp ON pp.referencia = p.referencia' |
||||
173 | . ' AND pp.codproveedor = ' . $dataBase->var2str(self::$codproveedor) |
||||
174 | . ' AND pp.coddivisa = ' . $dataBase->var2str(self::$coddivisa) |
||||
175 | . ' WHERE p.secompra = true AND p.bloqueado = false'; |
||||
176 | |||||
177 | if (self::$codfabricante) { |
||||
178 | $sql .= ' AND codfabricante = ' . $dataBase->var2str(self::$codfabricante); |
||||
179 | } |
||||
180 | |||||
181 | if (self::$codfamilia) { |
||||
182 | $codFamilias = [$dataBase->var2str(self::$codfamilia)]; |
||||
183 | |||||
184 | // buscamos las subfamilias |
||||
185 | $familia = new Familia(); |
||||
186 | if ($familia->loadFromCode(self::$codfamilia)) { |
||||
187 | foreach ($familia->getSubfamilias() as $fam) { |
||||
188 | $codFamilias[] = $dataBase->var2str($fam->codfamilia); |
||||
189 | } |
||||
190 | } |
||||
191 | |||||
192 | $sql .= ' AND codfamilia IN (' . implode(',', $codFamilias) . ')'; |
||||
193 | } |
||||
194 | |||||
195 | if (self::$comprado) { |
||||
196 | $sql .= ' AND pp.codproveedor = ' . $dataBase->var2str(self::$codproveedor); |
||||
197 | } |
||||
198 | |||||
199 | if (self::$query) { |
||||
200 | $words = explode(' ', self::$query); |
||||
201 | if (count($words) === 1) { |
||||
202 | $sql .= " AND (LOWER(v.codbarras) = " . $dataBase->var2str(self::$query) |
||||
203 | . " OR LOWER(v.referencia) LIKE '%" . self::$query . "%'" |
||||
204 | . " OR LOWER(pp.refproveedor) LIKE '%" . self::$query . "%'" |
||||
205 | . " OR LOWER(p.descripcion) LIKE '%" . self::$query . "%')"; |
||||
206 | } elseif (count($words) > 1) { |
||||
207 | $sql .= " AND (LOWER(v.referencia) LIKE '%" . self::$query . "%'" |
||||
208 | . " OR LOWER(pp.refproveedor) LIKE '%" . self::$query . "%' OR ("; |
||||
209 | foreach ($words as $wc => $word) { |
||||
210 | $sql .= $wc > 0 ? |
||||
211 | " AND LOWER(p.descripcion) LIKE '%" . $word . "%'" : |
||||
212 | "LOWER(p.descripcion) LIKE '%" . $word . "%'"; |
||||
213 | } |
||||
214 | $sql .= "))"; |
||||
215 | } |
||||
216 | } |
||||
217 | |||||
218 | switch (self::$orden) { |
||||
219 | case 'desc_asc': |
||||
220 | $sql .= " ORDER BY 3 ASC"; |
||||
221 | break; |
||||
222 | |||||
223 | case 'price_desc': |
||||
224 | $sql .= " ORDER BY 9 DESC"; |
||||
225 | break; |
||||
226 | |||||
227 | case 'ref_asc': |
||||
228 | $sql .= " ORDER BY 1 ASC"; |
||||
229 | break; |
||||
230 | |||||
231 | case 'stock_desc': |
||||
232 | $sql .= " ORDER BY 11 DESC"; |
||||
233 | break; |
||||
234 | } |
||||
235 | |||||
236 | return $dataBase->selectLimit($sql); |
||||
237 | } |
||||
238 | |||||
239 | protected static function idatributovalor(?int $id): string |
||||
240 | { |
||||
241 | if (empty($id)) { |
||||
242 | return ''; |
||||
243 | } |
||||
244 | |||||
245 | if (!isset(self::$idatributovalores[$id])) { |
||||
246 | $attValor = new AtributoValor(); |
||||
247 | $attValor->loadFromCode($id); |
||||
248 | self::$idatributovalores[$id] = $attValor->descripcion; |
||||
249 | } |
||||
250 | |||||
251 | return ', ' . self::$idatributovalores[$id]; |
||||
252 | } |
||||
253 | |||||
254 | protected static function modalProductos(Translator $i18n): string |
||||
255 | { |
||||
256 | return '<div class="modal" id="findProductModal" tabindex="-1" aria-hidden="true">' |
||||
257 | . '<div class="modal-dialog modal-xl">' |
||||
258 | . '<div class="modal-content">' |
||||
259 | . '<div class="modal-header">' |
||||
260 | . '<h5 class="modal-title"><i class="fas fa-cubes fa-fw"></i> ' . $i18n->trans('products') . '</h5>' |
||||
261 | . '<button type="button" class="close" data-dismiss="modal" aria-label="Close">' |
||||
262 | . '<span aria-hidden="true">×</span>' |
||||
263 | . '</button>' |
||||
264 | . '</div>' |
||||
265 | . '<div class="modal-body">' |
||||
266 | . '<div class="form-row">' |
||||
267 | . '<div class="col-sm mb-2">' |
||||
268 | . '<div class="input-group">' |
||||
269 | . '<input type="text" name="fp_query" class="form-control" id="productModalInput" placeholder="' . $i18n->trans('search') |
||||
270 | . '" onkeyup="return purchasesFormActionWait(\'find-product\', \'0\', event);"/>' |
||||
271 | . '<div class="input-group-append">' |
||||
272 | . '<button class="btn btn-primary btn-spin-action" type="button" onclick="return purchasesFormAction(\'find-product\', \'0\');">' |
||||
273 | . '<i class="fas fa-search"></i></button>' |
||||
274 | . '</div>' |
||||
275 | . '</div>' |
||||
276 | . '</div>' |
||||
277 | . '<div class="col-sm mb-2">' . static::fabricantes($i18n) . '</div>' |
||||
278 | . '<div class="col-sm mb-2">' . static::familias($i18n) . '</div>' |
||||
279 | . '<div class="col-sm mb-2">' . static::orden($i18n) . '</div>' |
||||
280 | . '</div>' |
||||
281 | . '<div class="form-row">' |
||||
282 | . '<div class="col-sm">' |
||||
283 | . '<div class="form-check">' |
||||
284 | . '<input type="checkbox" name="fp_comprado" value="1" class="form-check-input" id="comprado" onchange="return purchasesFormAction(\'find-product\', \'0\');">' |
||||
285 | . '<label class="form-check-label" for="comprado">' . $i18n->trans('previously-purchased-from-supplier') . '</label>' |
||||
286 | . '</div>' |
||||
287 | . '</div>' |
||||
288 | . '</div>' |
||||
289 | . '</div>' |
||||
290 | . '<div class="table-responsive" id="findProductList">' . static::renderProductList() . '</div>' |
||||
291 | . '</div>' |
||||
292 | . '</div>' |
||||
293 | . '</div>'; |
||||
294 | } |
||||
295 | |||||
296 | protected static function modalProveedores(Translator $i18n, string $url): string |
||||
297 | { |
||||
298 | $trs = ''; |
||||
299 | $proveedor = new Proveedor(); |
||||
300 | $where = [new DataBaseWhere('fechabaja', null, 'IS')]; |
||||
301 | foreach ($proveedor->all($where, ['LOWER(nombre)' => 'ASC']) as $pro) { |
||||
302 | $name = ($pro->nombre === $pro->razonsocial) ? $pro->nombre : $pro->nombre . ' <small>(' . $pro->razonsocial . ')</span>'; |
||||
303 | $trs .= '<tr class="clickableRow" onclick="document.forms[\'purchasesForm\'][\'codproveedor\'].value = \'' |
||||
304 | . $pro->codproveedor . '\'; $(\'#findSupplierModal\').modal(\'hide\'); purchasesFormAction(\'set-supplier\', \'0\'); return false;">' |
||||
305 | . '<td><i class="fas fa-user fa-fw"></i> ' . $name . '</td>' |
||||
306 | . '</tr>'; |
||||
307 | } |
||||
308 | |||||
309 | return '<div class="modal" id="findSupplierModal" tabindex="-1" aria-hidden="true">' |
||||
310 | . '<div class="modal-dialog modal-dialog-scrollable">' |
||||
311 | . '<div class="modal-content">' |
||||
312 | . '<div class="modal-header">' |
||||
313 | . '<h5 class="modal-title"><i class="fas fa-users fa-fw"></i> ' . $i18n->trans('suppliers') . '</h5>' |
||||
314 | . '<button type="button" class="close" data-dismiss="modal" aria-label="Close">' |
||||
315 | . '<span aria-hidden="true">×</span>' |
||||
316 | . '</button>' |
||||
317 | . '</div>' |
||||
318 | . '<div class="modal-body p-0">' |
||||
319 | . '<div class="p-3">' |
||||
320 | . '<div class="input-group">' |
||||
321 | . '<input type="text" id="findSupplierInput" class="form-control" placeholder="' . $i18n->trans('search') . '" />' |
||||
322 | . '<div class="input-group-apend">' |
||||
323 | . '<button type="button" class="btn btn-primary"><i class="fas fa-search"></i></button>' |
||||
324 | . '</div>' |
||||
325 | . '</div>' |
||||
326 | . '</div>' |
||||
327 | . '<table class="table table-hover mb-0">' . $trs . '</table></div>' |
||||
328 | . '<div class="modal-footer bg-light">' |
||||
329 | . '<a href="EditProveedor?return=' . urlencode($url) . '" class="btn btn-block btn-success">' |
||||
330 | . '<i class="fas fa-plus fa-fw"></i> ' . $i18n->trans('new') |
||||
331 | . '</a>' |
||||
332 | . '</div>' |
||||
333 | . '</div>' |
||||
334 | . '</div>' |
||||
335 | . '</div>'; |
||||
336 | } |
||||
337 | |||||
338 | protected static function orden(Translator $i18n): string |
||||
339 | { |
||||
340 | return '<div class="input-group">' |
||||
341 | . '<div class="input-group-prepend"><span class="input-group-text"><i class="fas fa-sort-amount-down-alt"></i></span></div>' |
||||
342 | . '<select name="fp_orden" class="form-control" onchange="return purchasesFormAction(\'find-product\', \'0\');">' |
||||
343 | . '<option value="">' . $i18n->trans('sort') . '</option>' |
||||
344 | . '<option value="">------</option>' |
||||
345 | . '<option value="ref_asc">' . $i18n->trans('reference') . '</option>' |
||||
346 | . '<option value="desc_asc">' . $i18n->trans('description') . '</option>' |
||||
347 | . '<option value="price_desc">' . $i18n->trans('price') . '</option>' |
||||
348 | . '<option value="stock_desc">' . $i18n->trans('stock') . '</option>' |
||||
349 | . '</select>' |
||||
350 | . '</div>'; |
||||
351 | } |
||||
352 | |||||
353 | private static function subfamilias(Familia $family, Translator $i18n, int $level = 1): string |
||||
354 | { |
||||
355 | $options = ''; |
||||
356 | foreach ($family->getSubfamilias() as $fam) { |
||||
357 | $options .= '<option value="' . $fam->codfamilia . '">' |
||||
358 | . str_repeat('-', $level) . ' ' . $fam->descripcion |
||||
359 | . '</option>'; |
||||
360 | |||||
361 | // añadimos las subfamilias de forma recursiva |
||||
362 | $options .= static::subfamilias($fam, $i18n, $level + 1); |
||||
363 | } |
||||
364 | |||||
365 | return $options; |
||||
366 | } |
||||
367 | } |
||||
368 |