Compare commits

...

690 Commits

Author SHA1 Message Date
El Mau 34a981a2dd Fix: en mercancias en Carta porte al generar el PDF 2024-04-10 20:54:26 -06:00
El Mau 66549e271b Fix: en mercancias en Carta porte al generar el PDF 2024-04-10 20:54:01 -06:00
El Mau 884b10bd79 Fix in js 2024-04-02 10:59:54 -06:00
El Mau fd050159ba Fix in js 2024-04-02 10:59:23 -06:00
El Mau 8199667188 Fix in Carta Porte 3.0 2024-04-02 10:31:58 -06:00
El Mau 05d3f617eb Fix in Carta Porte 2024-04-02 10:31:28 -06:00
El Mau 0ec4f0c2c9 Add support for Carta Porte 3.0 2024-04-02 00:25:41 -06:00
El Mau 29bfb42abc PDF from Carta Porte v3 2024-04-02 00:20:44 -06:00
El Mau 7f129b84b2 Stamp Carta Porte v3 2024-04-01 14:09:57 -06:00
El Mau 13a3c106c6 UI for Carta Porte v3 2024-03-31 22:28:13 -06:00
El Mau 0c7abf634b Update changelog 2024-03-04 14:07:10 -06:00
El Mau f0c4423fc8 Add support for Comercio Exterior 2.0 2024-01-24 15:07:26 -06:00
El Mau d925587a98 PDF from CE in version 2.0 2024-01-24 13:45:23 -06:00
El Mau 510ebdd1e5 Stamp CE in version 2.0 2024-01-21 23:20:27 -06:00
El Mau d2e92098da Import from ODS 2024-01-18 22:29:49 -06:00
El Mau c1ce206835 Import from json 2024-01-17 23:49:58 -06:00
El Mau 1efa280920 Import from json 2024-01-16 22:51:58 -06:00
El Mau 6fd8f9e2ea Add UI for CE 2024-01-14 22:42:26 -06:00
El Mau e3a44e6400 Add filter by day 2023-12-26 21:38:22 -06:00
El Mau 390ec60fdd Add filter by day 2023-12-26 21:37:45 -06:00
El Mau 957160755a Fix issue #98 and #107 2023-12-20 18:55:18 -06:00
El Mau 070ee31a1b Update changelog 2023-12-20 18:54:25 -06:00
El Mau 2620159408 Fix issue #98 2023-12-20 18:51:38 -06:00
El Mau 4d9bc4a172 Fix issue #107 2023-12-20 18:36:44 -06:00
El Mau 17ed56e9d7 Fix for CFDI egreso for General Public 2023-11-05 22:15:17 -06:00
El Mau 5057ac57ae Fix for CFDI egreso for General Public 2023-11-05 22:13:45 -06:00
El Mau 410a7080da Modify name for Public RFC 2023-10-30 16:51:38 -06:00
El Mau edd8d560bd Update changelog and version 2023-10-30 00:12:40 -06:00
El Mau bd1699d082 Add support for change time zone 2023-10-30 00:02:48 -06:00
El Mau 6d4023bb17 Update SATA catalog 2023-10-29 22:40:05 -06:00
Mauricio beda45690f Fix in retention tax for RESICOs 2023-07-06 11:16:04 -06:00
Mauricio 8feba167af Fix in retention tax for RESICOs 2023-07-06 11:15:15 -06:00
Mauricio 4dbb797d99 Fix tax retention in pay complement 2023-06-14 21:42:17 -06:00
Mauricio cd424b71dc Update changelog 2023-06-14 20:20:30 -06:00
Mauricio ea13d11319 Fix - Retencion tax in pay complement 2023-06-14 20:19:21 -06:00
Mauricio d9c863820a Merge pull request 'Añade información de desarrollo al readme' (#105) from categulario/empresa-libre:improve-readme into develop
Reviewed-on: #105
2023-06-06 15:23:46 -06:00
Categulario 6815d6c64c
improve readme with information on how to run locally 2023-06-05 22:34:09 -06:00
Mauricio 402cb7d70c Fix #103 2023-06-05 16:25:37 -06:00
Mauricio a5f1114774 Update changelog 2023-06-05 16:25:07 -06:00
Mauricio 2588a5f0b8 Fix #103 2023-06-05 16:22:53 -06:00
Mauricio eeae157772 Fix in complement pays 2023-05-25 21:59:13 -06:00
Mauricio 7cad4093d4 Fix in global invoice 2023-04-20 13:21:19 -06:00
Mauricio 7caf6423e1 Fix in global invoice 2023-04-20 13:20:48 -06:00
Mauricio 8a3aea41eb Add index in tickets 2023-04-15 19:23:56 -06:00
Mauricio bd49356d3f Add index in tickets 2023-04-15 18:13:45 -06:00
Mauricio 3b54ef0a36 Fix in global invoice 2023-04-14 17:56:12 -06:00
Mauricio 497a4be392 Update version 2023-04-14 17:55:48 -06:00
Mauricio 7fc6264322 Fix in global invoice 2023-04-14 17:55:00 -06:00
Mauricio c5d0e97212 Fix: al obtener la clave del sat al facturar en lote 2023-04-01 15:10:07 -06:00
Mauricio 5bbad9ef58 Fix: al obtener la clave del sat al facturar en lote 2023-04-01 15:09:27 -06:00
Mauricio 8e7aa23d1b Validate exists partner in edit 2023-03-29 17:36:17 -06:00
Mauricio f3d8b1dae5 Fix issue #97 2023-03-29 13:32:31 -06:00
Mauricio 2c684ae6bd Fix issue #97 2023-03-29 13:31:23 -06:00
el Mau febea3f289 Fix #96 2023-03-21 10:56:55 -06:00
el Mau 5facb96662 Fix #96 2023-03-21 10:55:16 -06:00
el Mau 6411c2e51e Fix in taxes in invoice pay 2023-03-13 17:16:30 -06:00
el Mau eeb128fda6 Fix in taxes in invoice pay 2023-03-13 17:16:15 -06:00
el Mau a078e27703 Fix in taxes in invoice pay 2023-03-13 14:01:26 -06:00
el Mau 28ef53043f Fix in taxes in invoice pay 2023-03-13 13:59:24 -06:00
el Mau e956c243f7 Fix in invoice pay 2023-03-10 14:56:19 -06:00
el Mau 1b33413de2 Fix in invoice pay 2023-03-10 14:55:57 -06:00
el Mau 64541a84b9 Fix in invoice pay with tax IVA 0 2023-03-07 11:53:28 -06:00
el Mau 834c1faae6 Fix in invoice pay with tax IVA 0 2023-03-07 11:53:04 -06:00
el Mau affe57bfcd Add validate for cancel movement bank 2023-03-06 16:10:07 -06:00
el Mau 4dc54ade1e Add validate for cancel movement bank 2023-03-06 16:09:37 -06:00
el Mau e72739a5fe Add cancel invoice pay in admin list 2023-03-06 00:48:01 -06:00
el Mau dd7b9c1680 Add cancel invoice pay in admin list 2023-03-06 00:47:34 -06:00
el Mau 9823bd967f Fix for exempted tax 2023-03-03 01:38:37 -06:00
el Mau aee467d98f Fix for exempted tax 2023-03-03 01:38:19 -06:00
el Mau 64917527f7 Validate tax object 2023-03-01 22:24:26 -06:00
el Mau 5f56179ebb Validate tax object 2023-03-01 22:24:00 -06:00
el Mau 955a0348f8 Can select month in global invoice 2023-03-01 18:45:50 -06:00
el Mau 0826b0cea2 Can select month in global invoice 2023-03-01 18:45:21 -06:00
el Mau 8b0f9fbc64 Can select global options for public invoice 2023-03-01 18:17:56 -06:00
el Mau f3d827364b Can select global options for public invoice 2023-03-01 18:16:52 -06:00
el Mau 50cbb3bae8 Fix in tax IVA retention 2023-03-01 14:32:33 -06:00
el Mau a7c8d80219 Fix in tax IVA retention 2023-03-01 14:32:01 -06:00
el Mau ca9d7a02e3 Update requirements.txt 2023-02-24 14:08:14 -06:00
el Mau 31fcb63e51 Update requirements.txt 2023-02-24 14:07:44 -06:00
el Mau bd7a31ea8a Fix global invoice 2023-02-24 12:45:52 -06:00
el Mau 6a6b6ca395 Fix global invoice 2023-02-23 18:20:10 -06:00
el Mau 3148c5ba82 Fix type change in deposit 2023-02-22 11:07:38 -06:00
el Mau 5f62ad7750 Fix type change in deposit 2023-02-22 11:06:37 -06:00
el Mau ff44162622 Fix type change in deposit 2023-02-21 22:16:25 -06:00
el Mau a37b3a5c23 Fix type change in deposit 2023-02-21 22:09:42 -06:00
el Mau 4fdea6173b Fix invoice pay in others currencies 2023-02-20 19:15:40 -06:00
el Mau 968c2744ec Fix pay invoice in other currencies 2023-02-20 19:10:29 -06:00
el Mau c9d85ca2e7 Fix make PDF from pays 1.0 2023-02-19 14:00:06 -06:00
el Mau 93e64eafd8 Fix make PDF from pays 1.0 2023-02-18 12:56:22 -06:00
el Mau 1984103ff5 Fix make PDF from pays 1.0 2023-02-18 12:40:05 -06:00
el Mau e4ba06c0ff Fix in tax object 04 2023-02-17 14:24:33 -06:00
el Mau 38bb267e55 Fix in tax object 04 2023-02-17 14:24:17 -06:00
el Mau 602467c8e9 Fix in tax object 04 2023-02-17 13:44:42 -06:00
el Mau 4020237f68 Fix in tax object 04 2023-02-17 13:43:43 -06:00
el Mau 933c9820e6 Fix with tax exento 2023-02-16 23:38:03 -06:00
el Mau 51daf0ad5e Stamp with tax exento 2023-02-16 23:09:35 -06:00
el Mau 709c524830 Show message when delete product 2023-02-16 22:30:08 -06:00
el Mau 434e15bb5b Fix in cancel with Finkok 2023-02-08 21:43:38 -06:00
el Mau ae5949c529 Fix in cancel with Finkok 2023-02-08 19:25:53 -06:00
el Mau af5fa3c812 Fix in templates 2023-02-01 22:45:48 -06:00
el Mau 6d399fcb39 Fix in templates 2023-02-01 22:45:24 -06:00
el Mau 8003fc42b9 Add template in json for 4.0 2023-02-01 22:27:13 -06:00
el Mau 7a0fb2b243 Add template in json for 4.0 2023-02-01 22:26:10 -06:00
el Mau 83bebde169 Fix use cfdi P01 2023-02-01 08:56:55 -06:00
el Mau 76d5f51d78 Fix use cfdi P01 2023-02-01 08:56:28 -06:00
el Mau 5f641c632e Get message error in import invoice by lote 2023-01-31 22:07:43 -06:00
el Mau 85eb7cd58c Get message error in import invoice by lote 2023-01-31 22:07:06 -06:00
el Mau 1c11a1b013 Fix get sum by tax ISR 2023-01-30 22:16:07 -06:00
el Mau 701bb68478 Fix sum for ISR tax 2023-01-30 22:10:25 -06:00
el Mau f13491d983 Fix get sum basy pay for IVA 2023-01-30 20:12:09 -06:00
el Mau 4020365616 Fix get base pay 2023-01-30 20:09:57 -06:00
el Mau a90f218c76 Fix node tax in invoice pay 2023-01-27 12:00:36 -06:00
el Mau 37995befd8 Fix node tax in invoice pay 2023-01-27 12:00:09 -06:00
el Mau 746c827492 Validate regimen fiscal in pay invoice 2023-01-23 16:18:11 -06:00
el Mau 3cea54c07c Validate regimen fiscal in pay invoice 2023-01-23 16:17:47 -06:00
el Mau 661eff1dc3 Validate regimen fiscal in pay invoice 2023-01-23 16:05:38 -06:00
el Mau cd11456ec3 Validate regimen fiscal in pay invoice 2023-01-23 16:05:22 -06:00
el Mau 2526a8f5aa Validate regimen fiscal in pay invoice 2023-01-23 15:39:04 -06:00
el Mau 0a13004419 Validate regimen fiscal in pay invoice 2023-01-23 15:38:28 -06:00
el Mau 296874a9b1 Admin regimenes 2023-01-22 12:57:35 -06:00
el Mau 34b1af1319 Admin regimenes 2023-01-21 23:19:44 -06:00
el Mau 5fbf80fb92 Show keys in invoice 2023-01-21 20:19:28 -06:00
el Mau b56fee5f73 Show key by regimen in invoice 2023-01-21 20:06:31 -06:00
el Mau c9ca45b60d Add keys in regimenes fiscales 2023-01-21 19:46:06 -06:00
el Mau 86e7f50621 Fix in validate CP 2023-01-13 22:25:48 -06:00
el Mau 2cef108856 Fix in validate CP 2023-01-13 22:21:03 -06:00
el Mau 260ba62b2e Fix in validate CP 2023-01-12 12:02:02 -06:00
el Mau 76d15e482b Fix in validate CP 2023-01-12 12:01:37 -06:00
el Mau 8e2446e8f5 Fix in complement pay without taxes 2023-01-12 00:33:39 -06:00
el Mau 482a0385cd Fix in complement pay without taxes 2023-01-12 00:33:11 -06:00
el Mau 29e02e649d Fix error in nomina 2023-01-11 00:27:42 -06:00
el Mau 5aece843bf Fix error in nomina 2023-01-11 00:24:35 -06:00
el Mau d47e059d93 CFDI 4.0 2023-01-10 00:07:17 -06:00
el Mau 89f79de9b6 Add template for donatarias 2023-01-10 00:06:40 -06:00
el Mau fbaa85f13a Fix #84 2023-01-09 23:11:52 -06:00
el Mau bed6039fff Fix #84 2023-01-09 17:46:40 -06:00
el Mau acbaecbfc5 Fix in preinvoice 2023-01-09 15:18:08 -06:00
el Mau 8dddb7b293 Update changelog 2023-01-08 19:29:36 -06:00
el Mau 24777f691e CFDI 4.0 2023-01-07 07:37:32 -06:00
el Mau 1d270aa478 Add templates 2023-01-06 21:42:46 -06:00
el Mau 8872af8c50 Fix in unit in invoice 2023-01-06 19:04:50 -06:00
el Mau d57ded161c Proporcional taxes in pays complements 2023-01-04 18:29:30 -06:00
el Mau 0c8d6d3cea Fix #83 2023-01-04 13:02:33 -06:00
el Mau f14c1f74d8 PDF for pays complement 2023-01-02 22:59:39 -06:00
el Mau 210f50a7d7 Add months in global invoice 2023-01-02 14:56:34 -06:00
el Mau 5418b23200 Plantillas 2023-01-01 22:58:58 -06:00
el Mau a13c7c0a1d Factura global 2022-12-31 17:30:01 -06:00
el Mau a6276a33fb Update temaple for Leyendas Fiscales 2022-10-27 22:37:05 -05:00
el Mau e3bd1e8871 Fix - Query SAT 2022-10-25 20:22:48 -05:00
el Mau 2ddb3d6b75 Fix - Cancel v4.0 2022-10-25 14:59:37 -05:00
Mauricio Baeza 4cda9f7f21 Update CP Db 2022-08-02 22:13:05 -05:00
Mauricio Baeza 7c184c9513 Update CP db 2022-08-01 21:31:44 -05:00
Mauricio Baeza aea8aeaecf Fix in import employes 2022-06-17 13:30:21 -05:00
Mauricio Baeza e08e4e038f Set name client to upper case 2022-06-09 13:50:33 -05:00
Mauricio Baeza 496dcf7162 Add some complements 2022-06-05 20:24:08 -05:00
Mauricio Baeza f8cd99084a Stamp Nomina with Cfdi 4.0 2022-06-04 21:52:28 -05:00
Mauricio Baeza 1e824bd841 Fix set current regimen in edit 2022-06-02 22:46:31 -05:00
Mauricio Baeza bc0cd9f3e1 Fix get data foro version 3.3 2022-05-31 22:14:17 -05:00
Mauricio Baeza ae259e461b Add template for CFDI 4.0 2022-05-30 13:30:47 -05:00
Mauricio Baeza 1a507d2eeb Add template for CFDI 4.0 2022-05-29 22:57:26 -05:00
Mauricio Baeza f766f92618 Minor changes 2022-05-25 23:18:21 -05:00
Mauricio Baeza ad56356a6f Quitar referencia a paquetes 2022-05-16 14:44:42 -05:00
El Mau c6cf33c4c4 Obtener datos de periodicidad para factura glbal 2022-04-18 21:45:30 -05:00
El Mau dbc3910297 Guardar periodicidad de factura global 2022-04-17 16:33:50 -05:00
El Mau 6c78a282fe Agregar periodicidad en UI para factura del día 2022-04-17 16:01:05 -05:00
El Mau f8c2c5e2d6 Agregar objeto de impuestos a productos 2022-04-16 21:58:42 -05:00
El Mau 7d40e79f3c Quitar validacion de empaques 2022-04-15 22:13:49 -05:00
El Mau a36034a476 Agregar controles para objeto de impuesto en productos 2022-04-14 23:01:02 -05:00
El Mau de2ab5cedd Obtener regimen fiscal del receptor al facturar desde tickets 2022-04-11 22:47:37 -05:00
El Mau b60e2d6a37 Timbrado con público en general 2022-04-07 21:31:42 -05:00
El Mau d9021cca4a Seleccionar regimen para público en general 2022-04-05 22:05:16 -05:00
El Mau 7bbef31936 Regresar regimenes del cliente al seleccionar 2022-04-03 23:00:02 -05:00
El Mau 74e7f12088 Regresar CP del cliente al refacturar 2022-04-02 23:13:37 -06:00
El Mau 20c0757f04 Regresar productos en orden al refacturar 2022-04-02 23:13:37 -06:00
El Mau 3a5fbc609b Regresar productos en orden al refacturar 2022-04-01 09:50:10 -06:00
El Mau 5e888d2337 Regresar productos en orden al refacturar 2022-04-01 09:49:15 -06:00
El Mau d97fd4867a Cambiar URLs para timbrado con Comercio Digital 2022-03-29 18:27:40 -06:00
El Mau e58b8f90af Cambiar demo de Finkok a https 2022-03-29 17:29:21 -06:00
El Mau 50d4a3f4b7 Soporte inicial para CFDI 4.0 2022-03-29 15:40:14 -06:00
El Mau 1978edfaf0 Tablas para borrar 2022-03-28 22:40:41 -06:00
El Mau 7ca87d1811 Timbrado de Complemento de Pagos 2.0 2022-03-28 22:40:41 -06:00
El Mau a7bc6d6f6c Agregar xlst para pagos 2.0 2022-03-28 22:40:41 -06:00
El Mau 1991c68b3b Soporte basico para Comercio Exterior 2022-03-28 22:39:55 -06:00
El Mau bebcd29710 Agregar cadena para Cfdi 4 2022-03-28 22:37:08 -06:00
El Mau de856f28ab Soporte basico para complemento Comercio Exterior 2022-03-28 21:34:10 -06:00
El Mau e726cda085 Soporte basico para complemento Comercio Exterior 2022-03-28 21:33:39 -06:00
El Mau eee386a97b Soporte basico para complemento Comercio Exterior 2022-03-17 21:22:27 -06:00
El Mau ae21403c59 Error al timbrar nomina 2022-03-10 20:26:27 -06:00
El Mau 110d41cf6e Actualizar VERSION 2022-03-10 20:25:51 -06:00
El Mau bd6fb65a1b Fix - Problema al timbra nómina con Comercio Digital 2022-03-10 19:24:29 -06:00
El Mau b68d79d0ca Fix issue #54 2022-02-18 14:59:01 -06:00
El Mau 670aca3886 Fix - Issue #54 2022-02-18 14:57:13 -06:00
El Mau 68c0203039 Fix issue #53 2022-02-15 23:51:27 -06:00
El Mau b2cdd0efbe Fix - Issue #53 2022-02-15 23:50:02 -06:00
El Mau 51af15f311 Error al generar Carta Porte sin remolque 2022-02-01 21:31:49 -06:00
El Mau edf35aa5ce Error al cancelar con Finkok 2022-02-01 21:31:06 -06:00
El Mau b19d087d10 Error al generar Carta Porte sin remolque 2022-01-31 18:48:43 -06:00
El Mau 64ef75fbf5 Mejoras en Carta Porte 2022-01-30 14:50:05 -06:00
El Mau d6a8c1e3fa Actualizar lista de cambios 2022-01-30 14:48:32 -06:00
El Mau a7080bf954 Agregar validación para distancia en origen de Carta Porte 2022-01-30 14:47:34 -06:00
El Mau 3ddf99075e Reporte #49, arreglado 2022-01-29 20:47:30 -06:00
El Mau bd6ba5d4d0 Mejoras en Carta Porte 2022-01-27 22:18:28 -06:00
El Mau 6a18934b19 Actualizar lista de cambios 2022-01-27 22:17:41 -06:00
El Mau 61548c9135 Buscar Estado y Municipio por CP en Carta Porte 2022-01-27 22:14:54 -06:00
El Mau fe3f743e32 Fix - Al generar PDF de carta porte sin remolque 2022-01-27 18:34:55 -06:00
El Mau c83e6981ae Agregar tipos de persimo SCT para Carta Porte 2022-01-27 13:23:00 -06:00
El Mau 39b9af125c Fix - Issue #45 2022-01-27 13:10:16 -06:00
El Mau dd606be46b Arreglado el error al cancelar con CD 2022-01-26 22:32:38 -06:00
El Mau 34df8882b3 Actualizar lista de cambios 2022-01-26 22:28:15 -06:00
El Mau e992103c57 Fix - Issue #44 2022-01-26 18:12:18 -06:00
El Mau 8f74d24b14 Fix - Issue #42 2022-01-26 18:01:27 -06:00
El Mau 480ec57d1e Error al timbrar Carta Porte 2022-01-25 19:33:05 -06:00
El Mau a38247727c Error al timbrar Carta Porte 2022-01-25 19:12:41 -06:00
El Mau 702aa264d8 Agregar certificado original 2022-01-24 17:05:41 -06:00
El Mau 0422eece40 Prueba de cancelación con UUID 2022-01-24 15:45:40 -06:00
El Mau 12774af7ac Quitar nodo KeyInfo del XML de cancelación 2022-01-24 12:47:57 -06:00
El Mau b16eabd773 Quitar nodo KeyInfo del XML de cancelación 2022-01-24 12:43:28 -06:00
El Mau 1bab1cb23c Quitar todos los saltos de línea del XML de cancelación 2022-01-24 12:37:42 -06:00
El Mau 15a05e38f7 Agregar, de nuevo KeyInfo del XML de cancelación 2022-01-24 12:31:10 -06:00
El Mau a0a8e0ce62 Quitar KeyInfo del XML de cancelación 2022-01-24 12:21:21 -06:00
El Mau 825e23e369 Mostrar el request enviado 2022-01-24 12:15:27 -06:00
El Mau 121831a139 Quitar saltos de línea en XML de cancelación 2022-01-24 12:08:17 -06:00
El Mau c09a5749da Quitar declaración de enconding en XML de cancelación 2022-01-24 12:04:26 -06:00
El Mau 01ccbcabd5 Cambio de NameSpace en XML de cancelación 2022-01-24 11:32:01 -06:00
El Mau cc0eee1443 Fix - Issue #40 2022-01-23 23:11:08 -06:00
El Mau 7a88c4b97f Fix - Issue #40 2022-01-23 23:10:28 -06:00
El Mau 0e7db2b711 Verificar cancelación con certificados en CD 2022-01-22 22:16:52 -06:00
El Mau 65851182c3 Verificar cancelación con certificados en CD 2022-01-22 22:02:02 -06:00
El Mau 2de98b9b92 Verificar cancelación con certificados en CD 2022-01-22 21:54:31 -06:00
El Mau 5a24bc159d Verificar cancelación con certificados en CD 2022-01-22 21:35:53 -06:00
El Mau f84721716c Verificar cancelación con certificados en CD 2022-01-22 21:21:55 -06:00
El Mau 8b91532b82 Verificar cancelación con certificados en CD 2022-01-22 21:11:18 -06:00
El Mau 0a98338fad Fix - Issue #40 2022-01-22 20:24:06 -06:00
El Mau 7bcf6d6e3c Agregar columna método de pago al listado de facturas 2022-01-22 20:17:42 -06:00
El Mau dbc8717575 Verificar cancelación con certificados en CD 2022-01-22 20:04:12 -06:00
El Mau 0adcd7f30f Verificar cancelación con certificados en CD 2022-01-22 20:01:53 -06:00
El Mau d237b33020 Verificar cancelación con certificados en CD 2022-01-22 19:47:41 -06:00
El Mau 5b997f7858 Verificar cancelaion con certificados en CD 2022-01-22 19:34:40 -06:00
El Mau a609c0c6f5 Actualizar cancelación con XML firmado con CD 2022-01-21 17:09:29 -06:00
El Mau d70cae64b7 Actualizar cancelación con XML firmado con CD 2022-01-21 17:00:59 -06:00
El Mau 9daf07693a Corregir error al enviar correo 2022-01-20 17:04:35 -06:00
El Mau e40acd28ba Corregir el error al enviar correo 2022-01-20 17:02:11 -06:00
El Mau 88dd9ca04b Corregir el error al enviar correo 2022-01-20 13:22:51 -06:00
El Mau d2f879c224 Importar carta porte desde json 2022-01-20 00:10:22 -06:00
El Mau 4922010caf Importar carta porte desde json 2022-01-20 00:06:05 -06:00
El Mau ff8bc31f50 Agregar opción STARTTLS para envío de correo 2022-01-19 15:03:26 -06:00
El Mau e795e87461 Agregar opción STARTTLS para envío de correo 2022-01-19 14:58:30 -06:00
El Mau d2c361e174 Representación impresa para Carta Porte 2022-01-19 13:30:22 -06:00
El Mau 6b0ca817a3 Agregar plantilla predeterminada para Carta Porte 2022-01-19 13:26:43 -06:00
El Mau 84fd8f57df Actualizar lista de cambios 2022-01-19 13:23:30 -06:00
El Mau f105f2a0fa Regimen fiscal desde emisor para CFDIs de pago 2022-01-19 13:10:30 -06:00
El Mau ea145c630b Primera versión completa de la representación impresa de la Carta Porte 2022-01-19 00:55:37 -06:00
El Mau 88bb6d9411 Agregar ubicaciones a representación impresa de Carta Porte 2022-01-19 00:17:29 -06:00
El Mau 0498217b65 Iniciar representación impresa de Carta Porte 2022-01-18 23:28:52 -06:00
El Mau 581e8bbdc5 Se agrega nodo para remolques 2022-01-17 21:49:35 -06:00
El Mau c79e8492d3 Copiar mercancias del CFDI 2022-01-16 22:20:45 -06:00
El Mau f9df0d34d0 Agregar eventos para agregar mercancias 2022-01-15 21:52:41 -06:00
El Mau f06022ac69 Agregar botón de comando para agregar mercacías en Carta Porte 2022-01-14 21:54:17 -06:00
El Mau 074cdc475f Agregar nodo para domicilio en Carta Porte 2022-01-12 21:42:02 -06:00
El Mau 0f041ed975 Agregar nodo para domicilio en Carta Porte 2022-01-11 21:49:28 -06:00
El Mau 6de30c3417 Actualizar lista de cambios 2022-01-10 14:28:16 -06:00
El Mau 8bbd2ba62b Actualizar lista de cambios 2022-01-10 14:10:17 -06:00
El Mau 00c58d9b41 Nuevo método para subir las plantillas 2022-01-10 13:39:35 -06:00
El Mau a3d291c893 Primera versión mínima de Carta Porte timbrada 2022-01-09 23:52:05 -06:00
El Mau 86bc032413 Nuevos controles para subir las plantillas 2022-01-08 21:24:19 -06:00
El Mau a91feb15d7 Agregar nuevos regimenes fiscales 2022-01-07 22:59:33 -06:00
El Mau 3ffc54f966 Modificar selector emergente para el calendario 2022-01-06 21:15:11 -06:00
El Mau b3663dfcc6 Modificar selector emergente para el calendario 2022-01-05 09:42:40 -06:00
El Mau 3cc11430d7 Cambio de formato del QR para plantilla json 2022-01-04 22:40:41 -06:00
El Mau 4ae5197ced Cambios en cancelación para Comercio 2022-01-04 14:29:00 -06:00
El Mau bf601dfcef Cambios en cancelación para Finkok 2022-01-03 23:06:55 -06:00
El Mau 481594839d Guardar datos para carta porte 2022-01-03 19:14:20 -06:00
El Mau 7b2467f99a Iniciar validaciones para carta porte 2022-01-01 21:48:02 -06:00
El Mau 2f22ad4cc8 Nuevos controles para carta porte terminada 2021-12-30 19:41:40 -06:00
El Mau 46d6329754 Resuelto: ticket #29 2021-12-30 11:56:22 -06:00
El Mau 2a2689a61b Sincronizar productos para carta porte 2021-12-29 22:02:17 -06:00
El Mau 76663fdd67 Agregar evento al cambiar de pestaña 2021-12-28 22:26:05 -06:00
El Mau 54ab86a089 Ocultar columna temporalmente 2021-12-27 21:33:34 -06:00
El Mau 7fe5251153 Agregar controles para Carta Porte 2021-12-25 23:00:23 -06:00
El Mau fe4829c6b8 Agregar controles para Carta Porte 2021-12-25 17:48:08 -06:00
El Mau bb90b3f6d7 Nuevos controles para carta porte 2021-12-21 23:01:44 -06:00
El Mau f4779dbb99 Validar que se seleccionen los dos archivos de los certificados 2021-12-17 21:14:23 -06:00
El Mau 47ec5ad360 Resolver conflictos 2021-12-12 22:30:15 -06:00
El Mau 80957afb84 Actualizar lista de cambios 2021-12-12 21:51:34 -06:00
El Mau b9af99aad6 Cancelar con certificados solo en modo depuración 2021-12-12 14:56:59 -06:00
El Mau 43e932e445 Consultar estatus del SAT en nómina 2021-12-12 14:46:53 -06:00
El Mau 8a151d42ad Corregir error al cancelar nomina 2021-12-12 13:51:51 -06:00
El Mau db77f6972d Corregir error al generar factura del día por ticket 2021-12-10 14:11:54 -06:00
El Mau ef2314880f Cambiar tipo de campo al campo Folio de la tabla Facturas 2021-12-09 22:56:29 -06:00
El Mau 1a1cb1173e Agregar XLST para Carta Porte 2021-12-04 22:05:20 -06:00
El Mau fe26744a8f Mover solo los tickets seleccionados al facturarlos 2021-12-04 21:56:00 -06:00
El Mau 69402e03bb Agregar archivos requeridos para CartaPorte 2.0 2021-12-03 21:41:37 -06:00
El Mau 4a84654117 Validar existencia por almacen 2021-11-29 21:57:32 -06:00
El Mau 81428c4f8e Cantidad a decimal al ajustar inventario 2021-11-28 15:29:57 -06:00
El Mau 28ef107949 Agregar cancelación con certificados con el pac CD 2021-11-26 13:14:43 -06:00
El Mau e372f064b4 Agregar declaración de encoding XML para cancelación 2021-11-25 16:41:30 -06:00
El Mau 46efb3693c Agregar declaración de encoding XML para cancelación 2021-11-25 14:40:37 -06:00
El Mau d2bacc3b6b Agregar declaración de encoding XML para cancelación 2021-11-25 12:51:49 -06:00
El Mau 264090f2a6 Remover nodo KeyValue en XML para cancelación 2021-11-25 10:22:23 -06:00
El Mau 425cd53df1 Remover nodo KeyValue en XML para cancelación 2021-11-24 16:02:48 -06:00
El Mau b7e8bb3cff Cambio en el formato del número de serie del certificado en el XML de cancelación 2021-11-24 15:53:40 -06:00
El Mau 1df477e0b1 Modificaciones menores a la plantilla XML para cancelación 2021-11-24 14:55:41 -06:00
El Mau 9b09fbbcd1 Resuelto - establecer 0 cuando descuento es None 2021-11-22 19:06:57 -06:00
El Mau f793cd2240 Resuelto - Obtener id de almacen origen 2021-11-22 09:16:28 -06:00
El Mau 54f2a574a3 Agregar método para importar existencias 2021-11-21 22:26:34 -06:00
El Mau 219f7c6712 Comentar lineas al firmar XML 2021-11-20 22:08:05 -06:00
El Mau 342f64a18b Resuelto - Quitar saltos de línea en XML firmado para cancelar 2021-11-18 21:45:54 -06:00
El Mau e880256cde Actualizar requerimientos 2021-11-18 21:35:09 -06:00
El Mau 3a1cb8d142 Actualizar vínculos en main 2021-11-17 19:38:09 -06:00
El Mau 42a840f85c Actualizar vínculos en main 2021-11-17 18:28:43 -06:00
Mauricio Baeza 2e5f4ac27e Get details from ticket 2021-10-30 15:08:32 -05:00
Mauricio Baeza 98f091a347 Start event for ticket from ticket 2021-10-29 22:06:53 -05:00
Mauricio Baeza 82ec2faac5 Fix link to blog 2021-10-28 21:23:06 -05:00
Mauricio Baeza 11c0cc4899 Add button for regenerate ticket 2021-10-28 21:20:58 -05:00
Mauricio Baeza 1c9c829296 Add link to repository 2021-10-26 23:17:01 -05:00
Mauricio Baeza 03f26b65e4 Add link to repository 2021-10-24 21:35:27 -05:00
Mauricio Baeza 00f2b2b126 Start new doc 2021-10-23 22:03:43 -05:00
Mauricio Baeza c77438216d Start new doc 2021-10-23 21:46:04 -05:00
Mauricio Baeza b02b2b0e63 Change label in certificates 2021-10-23 21:14:15 -05:00
Mauricio Baeza 75788474ba Add controller for warehouse movement 2021-10-14 19:20:23 -05:00
Mauricio Baeza 866e8c40b9 Add UI for warehouse movement 2021-10-13 21:13:08 -05:00
Mauricio Baeza c64de2bbb9 Update inventory in cancel tickets 2021-10-05 15:11:27 -05:00
Mauricio Baeza cd35884999 Add warehouse in detail tickets 2021-10-04 22:21:49 -05:00
Mauricio Baeza c4e29e47fa Update inventory in cancel invoice 2021-10-03 22:21:01 -05:00
Mauricio Baeza 00cbe4d557 Save warehouse in product details 2021-10-03 22:12:05 -05:00
Mauricio Baeza a95a6842f9 Save warehouse in product 2021-10-02 22:23:51 -05:00
Mauricio Baeza 30a4a276dd Update inventory in tickets 2021-09-26 21:20:08 -05:00
Mauricio Baeza 416bc65174 Can products without taxes 2021-09-14 21:53:00 -05:00
Mauricio Baeza 3dd88f14d6 Update version 2021-09-14 21:51:58 -05:00
Mauricio Baeza fb24346601 Can add or edit products without taxes 2021-09-14 21:49:21 -05:00
Mauricio Baeza f792b79655 Get exists by warehouse 2021-09-05 20:29:08 -05:00
Mauricio Baeza 2055a904f6 Add dialog for show exists in warehouse 2021-09-05 19:48:05 -05:00
Mauricio Baeza 7a1fd8fcaf Add command button for show details exists in warehouses 2021-09-04 21:59:24 -05:00
Mauricio Baeza cd22a5a24d Add new documentation 2021-09-03 22:13:25 -05:00
Mauricio Baeza 25e86cd28c Remove modifi precition in decimal context 2021-09-01 21:45:21 -05:00
Mauricio Baeza 4aad1a94eb Replace save for update in invoice 2021-08-31 21:47:05 -05:00
Mauricio Baeza 229be3b415 Fix pass id product in update inventory 2021-08-30 23:23:53 -05:00
Mauricio Baeza bc53171969 Update inventory 2021-08-30 22:57:31 -05:00
Mauricio Baeza 61a8937eb3 Add product by warehouse 2021-08-23 15:49:29 -05:00
Mauricio Baeza be75abeb54 Get wharehouse in products 2021-08-22 22:33:04 -05:00
Mauricio Baeza 2c314a3891 Add select warehouse in add product 2021-08-11 22:10:23 -05:00
Mauricio Baeza 7fc1d42381 Set branch by user 2021-08-08 21:51:12 -05:00
Mauricio Baeza 0957cf673f Add dialog for set branch user 2021-08-04 23:00:23 -05:00
Mauricio Baeza f99adaf109 Clean branch for users 2021-08-03 22:13:19 -05:00
Mauricio Baeza 91cfbb0508 Add column 'In branch' for users 2021-08-03 20:08:57 -05:00
Mauricio Baeza 4f18e1e01f Show or hide column for super user 2021-08-01 23:03:32 -05:00
Mauricio Baeza 7e7b08b1c0 Add products without taxes 2021-07-26 22:40:59 -05:00
Mauricio Baeza 4006322f30 Fix issue #12 2021-07-26 22:30:37 -05:00
Mauricio Baeza 935483f7ee Fix issue #11 2021-07-26 22:08:20 -05:00
Mauricio Baeza 80b766783d Save warehouse in sucursal 2021-07-25 21:58:23 -05:00
Mauricio Baeza 8822687308 Show warehouse in sucursal 2021-07-25 21:45:59 -05:00
Mauricio Baeza 0512e0f6dd Add and delete warehouse 2021-07-25 21:18:01 -05:00
Mauricio Baeza 93f0d09f4d Fix name error in warehouse 2021-07-24 22:41:06 -05:00
Mauricio Baeza 870d95cb5a Get wharehouse 2021-07-23 22:29:22 -05:00
Mauricio Baeza 9fa35d5592 Add wharehouse 2021-07-23 22:01:59 -05:00
Mauricio Baeza 2bfe86973a Add new table WhareHouseProduct 2021-07-23 18:43:26 -05:00
Mauricio Baeza 896be35e3b Hide or show controls for warehouses 2021-07-22 22:25:07 -05:00
Mauricio Baeza f2af10c2df Add UI grid for warehouse 2021-07-22 21:45:36 -05:00
Mauricio Baeza 8f7aaac563 Add options for multi stock UI 2021-07-22 21:24:04 -05:00
Mauricio Baeza 8a615144a6 Only admins can add inventory 2021-07-21 22:04:13 -05:00
Mauricio Baeza 227204abec Only admins can add inventory 2021-07-21 21:37:31 -05:00
Mauricio Baeza 637c69b9c7 Update changelog 2021-07-10 13:25:04 -05:00
Mauricio Baeza 4f3bdbda95 Add inventory entries manually 2021-07-08 12:56:40 -05:00
Mauricio Baeza 34c467d26e Add validation for new stock 2021-07-05 15:56:00 -05:00
Mauricio Baeza d61672dac4 Add UI windows for add inventory manually 2021-07-05 15:21:03 -05:00
Mauricio Baeza 1aa6540ac1 Change pyqrcode for segno 2021-06-29 19:07:55 -05:00
Mauricio Baeza 1b87591f62 Add inventory entries 2021-06-17 22:33:06 -05:00
Mauricio Baeza 986020a4a3 Add partner products 2021-06-17 21:45:40 -05:00
Mauricio Baeza 3514944f5d Add products in inventory entries 2021-06-16 23:36:25 -05:00
Mauricio Baeza 9be913c47d Add inventory entries post 2021-06-15 23:45:11 -05:00
Mauricio Baeza b9d87f0343 Validate add products 2021-06-14 23:41:39 -05:00
Mauricio Baeza 585632882d Validate add products 2021-06-13 23:55:32 -05:00
Mauricio Baeza 920ff62e98 Add new table PartnerProducts 2021-06-13 23:12:07 -05:00
Mauricio Baeza dc61d3b010 Parse details from CFDI 2021-06-10 21:39:15 -05:00
Mauricio Baeza 62a0a82699 Refactory class for read and write CFDIs 2021-06-08 22:54:59 -05:00
Mauricio Baeza 702ac88b38 Refactory method for import file 2021-06-07 22:45:00 -05:00
Mauricio Baeza 535cc9d527 Add button for import products from CFDI 2021-06-06 22:33:46 -05:00
Mauricio Baeza cf35cd08cd Validate stock in ticket 2021-06-01 19:45:42 -05:00
Mauricio Baeza e9eeab8c2c Validate stock when invoice 2021-06-01 19:34:34 -05:00
Mauricio Baeza a518278b55 Ticket #5 2021-05-31 13:01:03 -05:00
Mauricio Baeza 0442019ea5 Ticket #5 2021-05-31 12:59:45 -05:00
Mauricio Baeza fa94e36e7f Delete sucursales 2021-05-25 21:37:56 -05:00
Mauricio Baeza 348be949ac Add sucursales 2021-05-25 20:36:27 -05:00
Mauricio Baeza 565f36be3a Option cancel only by admins 2021-05-24 12:54:11 -05:00
Mauricio Baeza 7062151e79 Actualizar archvio de cambios 2021-05-24 12:33:56 -05:00
Mauricio Baeza 5f1edc76ca Add RFC test 2021-05-12 19:43:35 -05:00
Mauricio Baeza 5729a1f83e Cancel by admin 2021-04-20 21:41:08 -05:00
Mauricio Baeza 1a9087b13a Fix ticket #4 2021-04-13 22:29:29 -05:00
Mauricio Baeza a2670cb92c Fix ticket #4 2021-04-13 22:29:04 -05:00
Mauricio Baeza a8667a5d4f Fix in validate cert 2021-02-26 14:32:43 -06:00
Mauricio Baeza 952dcba7ae Fix issue #3 2021-02-12 19:37:11 -06:00
Mauricio Baeza 676ff29b57 Fix - issue #3 2021-02-12 18:19:40 -06:00
Mauricio Baeza 12a24c1117 Fix issue #2 2021-02-12 12:23:34 -06:00
Mauricio Baeza e59941db34 Update version and changelog 2021-02-12 12:23:20 -06:00
Mauricio Baeza 0e881eb17a Fix get version in PDF nomina 2021-02-12 12:04:31 -06:00
Mauricio Baeza fa01e6cf01 Fix issue #1 2021-02-11 18:10:37 -06:00
Mauricio Baeza 51e2464141 Update version and changelog 2021-02-11 18:09:58 -06:00
Mauricio Baeza 3e43cc3b46 Fix - issue #1 2021-02-11 18:07:51 -06:00
Mauricio Baeza b5bdcbbeb3 Import clients form CSV 2021-02-10 23:02:12 -06:00
Mauricio Baeza 4f71dd0de3 Clean review methods 2021-02-10 23:01:30 -06:00
Mauricio Baeza 720c9f0cb1 Update changelog and version 2021-02-10 22:54:16 -06:00
Mauricio Baeza 66d740e8d1 Report log 2021-02-10 22:50:05 -06:00
Mauricio Baeza 892906c46f Import clients 2021-02-10 22:47:00 -06:00
Mauricio Baeza aa68225571 Read csv to dict 2021-02-10 22:34:34 -06:00
Mauricio Baeza 4f40bc3bfa Add option for import clients 2021-02-10 22:01:39 -06:00
Mauricio Baeza b03fbebe09 Fix get status sat, issue #422 2021-02-09 23:04:49 -06:00
Mauricio Baeza 3cdbe14287 Update changelog 2021-02-09 23:04:31 -06:00
Mauricio Baeza 0bbf0b438f Add try except 2021-02-09 23:04:02 -06:00
Mauricio Baeza c98cdd7fff Fix get status sat, issue #422 2021-02-09 23:01:28 -06:00
Mauricio Baeza f0b5fa5ae9 Fix - issue #422 2021-02-09 23:01:08 -06:00
Mauricio Baeza 537cecbb0b Fix get status sat, issue #422 2021-02-09 22:49:57 -06:00
Mauricio Baeza 7f44f7f26d Update changelog 2021-02-09 22:46:36 -06:00
Mauricio Baeza c1e1c5ad7c Fix - issue #422 2021-02-09 22:44:26 -06:00
Mauricio Baeza 3c574425eb Move get status sat 2021-02-09 22:34:15 -06:00
Mauricio Baeza 5b8cd0ecb2 Fix show version of Empresa Libre 2021-02-02 22:10:13 -06:00
Mauricio Baeza 05a51741b6 Fix - show version of EmpresaLibre 2021-02-02 22:09:12 -06:00
Mauricio Baeza b3e2671359 Update template 2021-02-02 21:49:10 -06:00
Mauricio Baeza 5c047ee9d5 Update changelog 2021-01-19 12:16:41 -06:00
Mauricio Baeza b680d728a7 Update changelog 2021-01-18 19:28:15 -06:00
Mauricio Baeza 431422361b Fix passed argument to pac 2021-01-18 19:06:59 -06:00
Mauricio Baeza 85e58c2728 Fix passed argument to pac 2021-01-18 18:41:03 -06:00
Mauricio Baeza 739ac08205 Add migrate auth 2021-01-13 19:15:38 -06:00
Mauricio Baeza 64adba1588 Add migrate auth 2021-01-13 19:14:54 -06:00
Mauricio Baeza de06f706a6 Fix get version in proforma 2021-01-11 14:43:50 -06:00
Mauricio Baeza 6785dfebf7 Fix get version in proforma 2021-01-11 14:43:28 -06:00
Mauricio Baeza aaccece897 Fix get folios 2021-01-10 19:18:48 -06:00
Mauricio Baeza 94f5df0723 Fix get folios 2021-01-10 19:18:13 -06:00
Mauricio Baeza f813fb4dd8 Fix set error in pac Finkok 2021-01-10 15:24:35 -06:00
Mauricio Baeza 49d5838822 Fix set error in oac Finkok 2021-01-10 15:24:11 -06:00
Mauricio Baeza 51b4386b24 Fix add backend in cert 2021-01-10 14:23:58 -06:00
Mauricio Baeza 38f3c125cd Fix add backend in cert 2021-01-10 14:23:39 -06:00
Mauricio Baeza e678083eea Fix add backend in cert 2021-01-10 14:21:51 -06:00
Mauricio Baeza b612991476 Fix add backend in cert 2021-01-10 14:21:32 -06:00
Mauricio Baeza 32679fced3 Fix in function name export cert 2021-01-10 14:17:32 -06:00
Mauricio Baeza 8e4bf56846 Fix in function name export cert 2021-01-10 14:17:01 -06:00
Mauricio Baeza 0084197906 Fix in get year for preinvoices 2021-01-08 20:53:29 -06:00
Mauricio Baeza ace4ef21a7 Fix get years in preinvoices 2021-01-08 19:58:14 -06:00
Mauricio Baeza 17fa99e45b Add migrate certificates 2021-01-06 22:15:30 -06:00
Mauricio Baeza e547ce0113 Change name from migrate cert 2021-01-06 22:14:59 -06:00
Mauricio Baeza 858fd829aa Update changelog 2021-01-06 22:13:02 -06:00
Mauricio Baeza 788a1723b4 Remove class for import from FacturaLibre 2021-01-06 21:44:02 -06:00
Mauricio Baeza 4b9df44dac Add migrate certificates 2021-01-06 21:30:31 -06:00
Mauricio Baeza cca598310b Fix in import conf for pacs 2021-01-05 18:53:13 -06:00
Mauricio Baeza 39071be43b Fix import conf in pacs 2021-01-05 18:43:34 -06:00
Mauricio Baeza e633f8e2bf Fix import conf in pacs 2021-01-05 18:16:18 -06:00
Mauricio Baeza 21fd903943 Refactory stamp and cancel 2021-01-05 17:32:38 -06:00
Mauricio Baeza fec1c8523a Update changelog 2021-01-05 17:32:03 -06:00
Mauricio Baeza 0a04ec6c26 Cancel old with Finkok 2021-01-03 19:44:52 -06:00
Mauricio Baeza a7945dba58 Cancel by rfc of pac 2021-01-02 22:23:33 -06:00
Mauricio Baeza 348a7f6ecb Add pac Finkok refactory 2021-01-02 18:16:15 -06:00
Mauricio Baeza cf189b08fa Add try in cert 2020-12-31 21:55:01 -06:00
Mauricio Baeza 9423aeef6c Cancel cfdi of nomina with xml signed 2020-12-31 21:11:22 -06:00
Mauricio Baeza 90eec635ce Cancel cfdi of pay with xml signed 2020-12-31 21:00:00 -06:00
Mauricio Baeza 8f15961d20 Fix - replace getchildren form list 2020-12-31 20:17:00 -06:00
Mauricio Baeza 8a8f05384b Stamp nomina 2020-12-31 20:10:32 -06:00
Mauricio Baeza a54ad8d760 Cancel sign xml 2020-12-31 15:08:49 -06:00
Mauricio Baeza 0389c0734f Clean methods to import from old FacturaLibre 2020-12-31 12:17:26 -06:00
Mauricio Baeza cb04910a84 Sign in memory 2020-12-31 12:01:41 -06:00
Mauricio Baeza 38c9c676af Remove old class cert 2020-12-31 00:06:50 -06:00
Mauricio Baeza e0d1f40a11 Remove old validate cert 2020-12-31 00:04:19 -06:00
Mauricio Baeza d8ecae2c8f Refactory upload certificates 2020-12-31 00:01:41 -06:00
Mauricio Baeza 85c5a37798 Refactory class certificates 2020-12-30 22:45:57 -06:00
Mauricio Baeza 56e52782f4 Refactory generate files 2020-12-29 22:05:02 -06:00
Mauricio Baeza aae856bb74 New class for Pac Comercio Digital 2020-12-29 21:53:51 -06:00
Mauricio Baeza 95399798f8 Stamp by Pac 2020-12-28 22:28:52 -06:00
Mauricio Baeza 75e4f2e1c0 Fix version in XSLT 2020-12-28 22:22:36 -06:00
Mauricio Baeza f02b6782be Move configuration for PACs 2020-12-28 22:14:30 -06:00
Mauricio Baeza bd7508fe6b Issue #415 2020-12-16 16:04:32 -06:00
Mauricio Baeza 1f3e51861d Update version 2020-09-17 13:53:01 -05:00
Mauricio Baeza 3a51a50c8e Update version 2020-09-17 13:52:31 -05:00
Mauricio Baeza 1c6f9cd5f7 Fix - Namespaces for IEDU 2020-09-17 13:46:41 -05:00
Mauricio Baeza b6c5c72df8 Fix - Namespaces for IEDU 2020-09-17 13:46:23 -05:00
Mauricio Baeza 8d815bf570 Update date in change log 2020-08-25 23:03:12 -05:00
Mauricio Baeza afced92aff Update date in change log 2020-08-25 23:02:54 -05:00
Mauricio Baeza 443b916056 Fix - Validate namespace 2020-08-25 15:17:59 -05:00
Mauricio Baeza 1d18d97b90 Update change log 2020-08-25 15:17:10 -05:00
Mauricio Baeza 43808efc91 Fix namespace in nomina 2020-08-25 14:15:07 -05:00
Mauricio Baeza 3ef195ed48 Mostrar totales 2020-04-16 22:35:41 -05:00
Mauricio Baeza 980a7aafdb Fix: nomina stamp asimilados 2020-03-30 19:04:50 -06:00
Mauricio Baeza 1e95b180e8 Fix: nomina stamp asimilados 2020-03-30 19:04:33 -06:00
Mauricio Baeza 267a96ebbc Global invoice by ticket 2020-03-08 15:27:53 -06:00
Mauricio Baeza 5e8d4d5fd9 Fix make PDF 2020-03-08 15:26:53 -06:00
Mauricio Baeza 8a293110ab Fix make PDF 2020-03-08 15:26:44 -06:00
Mauricio Baeza 4fcd7e18c0 Global invoice by ticket 2020-03-04 22:36:20 -06:00
Mauricio Baeza ed23a3531c Uncancel ticket when cancel invoice 2020-03-03 22:47:40 -06:00
Mauricio Baeza 82af00fedf Global invoice, get max payment type 2020-03-03 22:24:00 -06:00
Mauricio Baeza 763f3c21fb Support for tax legends 2020-03-02 17:27:28 -06:00
Mauricio Baeza 6b4eb36795 Tax legends in PDF 2020-03-02 17:27:02 -06:00
Mauricio Baeza 2877a68b92 Stamp fiscal leyends 2020-03-01 23:18:26 -06:00
Mauricio Baeza cca836bb6a Add UI for fiscal leyends 2020-02-29 23:51:14 -06:00
Mauricio Baeza 26e4ce3d13 Options for show documents 2020-02-25 21:52:17 -06:00
Mauricio Baeza 3166723cdc Options for show documents 2020-02-25 21:51:48 -06:00
Mauricio Baeza a202f12a17 Add filter by sucursal 2020-02-24 22:35:24 -06:00
Mauricio Baeza bf3ed47fac Update changelog 2020-02-24 22:34:54 -06:00
Mauricio Baeza b2f3cdd66e Filter by sucursal 2020-02-23 22:02:46 -06:00
Mauricio Baeza a17345c0fd Fix stamp nomina 2020-02-09 22:34:58 -06:00
Mauricio Baeza 7d7ca4eeba Fix stamp nomina 2020-02-09 22:34:36 -06:00
Mauricio Baeza d509bfb8be Fix new validate nomina SAT 2020-01-29 16:03:20 -06:00
Mauricio Baeza 0a006f4508 Fix new validate nomina SAT 2020-01-29 16:03:02 -06:00
Mauricio Baeza 71bd536cb1 Update catalog SAT 2020-01-27 22:40:57 -06:00
Mauricio Baeza 068c57c018 Add update SAT 2020-01-27 22:39:39 -06:00
Mauricio Baeza e94cda3577 Fix import conf.py 2020-01-24 10:02:24 -06:00
Mauricio Baeza f102cb7c01 Fix import conf.py 2020-01-24 10:01:55 -06:00
Mauricio Baeza 92e6a317ad Get folios by Pac 2020-01-22 22:30:11 -06:00
Mauricio Baeza 77b35f8322 Add new PAC 2020-01-22 15:25:40 -06:00
Mauricio Baeza 3f0daec6ad Change argument user for stamp 2020-01-22 13:21:53 -06:00
Mauricio Baeza a641024a86 Select Pac in admin 2020-01-22 12:48:15 -06:00
Mauricio Baeza f9a73dfd66 Add new PAC 2020-01-21 23:25:25 -06:00
Mauricio Baeza 2cc6e7046a Add new PAC 2020-01-21 23:25:13 -06:00
Mauricio Baeza fe09860922 Update catalogos SAT 2020-01-12 22:40:45 -06:00
Mauricio Baeza aeb045e76a Check unique clients 2020-01-11 22:14:38 -06:00
Mauricio Baeza 1c55fbd7c7 Fix #355 2020-01-07 21:48:57 -06:00
Mauricio Baeza e1b7e525df Fix #355 2020-01-07 00:34:11 -06:00
Mauricio Baeza 6f3d9cc3fa Fix - al crear PDF 2019-10-28 20:04:28 -06:00
Mauricio Baeza cff2294601 Fix - al generar PDF 2019-10-28 19:35:03 -06:00
Mauricio Baeza ce0e960534 Merge branch 'develop'
Fix #369
2019-08-29 09:13:43 -05:00
Mauricio Baeza af6b13fa67 Update version 2019-08-28 14:30:57 -05:00
Mauricio Baeza df901090a2 Fix #369 2019-08-28 14:28:48 -05:00
Mauricio Baeza a87c78fc6b Start changes for uncancel 2019-07-11 13:34:59 -05:00
Mauricio Baeza abbb4cc608 Merge branch 'develop'
Envío de nómina por correo
Actualización de catalogos del SAT
2019-04-23 23:12:25 -05:00
Mauricio Baeza a67d174782 Update Changelog 2019-04-23 23:11:49 -05:00
Mauricio Baeza 63ae4a5127 Modify Middleware 2019-04-17 22:38:51 -05:00
Mauricio Baeza 4574ff744f Envío de nómina por correo 2019-04-02 09:25:40 -06:00
Mauricio Baeza 163e0f50c9 Envío de nómina por correo 2019-04-01 23:09:32 -06:00
Mauricio Baeza 692477f41a Merge branch 'develop'
Actualización de catálogos del SAT en Nómina
2019-03-24 21:49:26 -06:00
Mauricio Baeza ae351b6148 Actualización de catálogos del SAT de Nómina 2019-03-24 20:40:47 -06:00
Mauricio Baeza 519a61e132 Merge branch 'develop'
Permitir editar la descripción en un movimiento bancario
Fix #343
2019-03-08 22:10:19 -06:00
Mauricio Baeza d7260a8a95 Permitir editar la descripción de un movimiento bancario 2019-03-08 22:06:16 -06:00
Mauricio Baeza 485dc4154e Fix #343 2019-03-08 19:40:53 -06:00
Mauricio Baeza 4bff2703a4 Merge branch 'develop'
Fix - Send pay invoice
2019-03-04 19:44:59 -06:00
Mauricio Baeza 2ee2b8be43 Fix - Send pay invoice 2019-03-04 19:44:42 -06:00
Mauricio Baeza 6cef8fe669 Merge branch 'develop'
Fix - In filter invoice by dates
2019-03-04 19:22:56 -06:00
Mauricio Baeza aad48639ee Fix - In filter invoice by dates 2019-03-04 19:22:28 -06:00
Mauricio Baeza 27a29d331c Delete files in render PDF 2019-03-03 23:01:31 -06:00
Mauricio Baeza 7a709f056c Merge branch 'categulario/empresa-libre-feature/virtualenv' into develop
Agregar env a gitignore
2019-02-25 13:18:40 -06:00
Mauricio Baeza 49f1c24df5 Mezclar gitignore 2019-02-25 13:14:52 -06:00
Mauricio Baeza 4a38410e8f Validación para que ISR sea de solo retención 2019-02-22 12:24:52 -06:00
Mauricio Baeza 2cacb786b6 Merge branch 'develop'
Error al enviar prefactura por correo
2019-02-20 23:40:07 -06:00
Mauricio Baeza 7f33252fa1 Error al enviar prefactura por correo 2019-02-20 23:39:47 -06:00
Mauricio Baeza 79cea5b092 Merge branch 'develop'
Soporte para complemento de divisas
2019-02-17 22:12:39 -06:00
Mauricio Baeza 9ea396b133 Cambio al generar un zip 2019-02-17 22:12:01 -06:00
Mauricio Baeza 4c2ea774b4 Descargar nómina en lote 2019-02-17 13:29:10 -06:00
Mauricio Baeza da41bb272e Filtro de facturas incluye cliente 2019-02-16 22:38:58 -06:00
Mauricio Baeza 8d7b42e368 Actulizar lista de cambios 2019-02-16 22:11:20 -06:00
Mauricio Baeza e292ba88b8 Mejora #329 2019-02-16 22:07:19 -06:00
Mauricio Baeza 7e73541c96 Buscar facturas por notas 2019-02-15 17:51:13 -06:00
Mauricio Baeza a0e1f83c25 Complemento divisas en PDF 2019-02-15 14:38:41 -06:00
Mauricio Baeza 8a4021ce49 Complemento divisas 2019-02-14 22:50:17 -06:00
Mauricio Baeza a4997be78d Actualizar vinculos 2019-02-14 20:17:03 -06:00
Mauricio Baeza 95d3345418 Notificación de acceso por correo 2019-02-05 22:12:19 -06:00
Mauricio Baeza f761ab7a5a Mostrar cantidad de empaques en PDF 2019-02-04 22:13:11 -06:00
Mauricio Baeza 5cdbb0aaa7 Agregar funciones para encriptar 2019-02-03 23:32:48 -06:00
Mauricio Baeza c9f9ea526f Cantidad de empaques al facturar 2019-02-03 22:43:27 -06:00
Mauricio Baeza 06170cb054 Cantidad por empaque en productos 2019-02-03 22:20:54 -06:00
Mauricio Baeza 43684b7fe9 Merge branch 'develop'
Fix - Al cancelar nómina
2019-01-23 13:33:32 -06:00
Mauricio Baeza d48122608b Fix - Al cancelar nómina 2019-01-23 13:33:11 -06:00
Mauricio Baeza 3d300146f1 Merge branch 'develop'
Permitir capturar folio manualmente
2019-01-17 22:10:17 -06:00
Mauricio Baeza 5ed281fd9d Permitir capturar folio manualmente 2019-01-17 22:00:07 -06:00
Mauricio Baeza dbf3a342bf Merge branch 'develop'
Guardar logos de emisor en carpeta correcta
2019-01-16 23:38:05 -06:00
Mauricio Baeza 43e643cccd Guardar logos del emisor en carpeta correcta 2019-01-16 23:37:51 -06:00
Mauricio Baeza 454de7bf1e Guardar logos del emisor en carpeta correcta 2019-01-15 23:16:34 -06:00
Mauricio Baeza 997dfe90ba Merge branch 'develop'
Generar PDF desde plantilla JSON
2019-01-15 00:51:05 -06:00
Mauricio Baeza 812e510660 Actualizar CHANGELOG.md 2019-01-15 00:47:15 -06:00
Mauricio Baeza 538a9f39ce Leyenda cancelada en PDF a partir de JSON 2019-01-15 00:45:08 -06:00
Mauricio Baeza cf0c4b8622 PDF a partir de JSON 2019-01-14 02:07:42 -06:00
Mauricio Baeza 7864e236db PDF a partir de JSON 2019-01-10 23:37:37 -06:00
Mauricio Baeza 00bdd2b1a2 Subir plantillas HTML y CSS 2018-11-20 23:47:53 -06:00
Mauricio Baeza 0d52e9b570 Factura HTML v1 2018-11-20 00:03:07 -06:00
Mauricio Baeza 7dc65a2a2b Soporte para factura en HTML 2018-11-19 01:03:48 -06:00
Mauricio Baeza ff0ee73a73 Merge branch 'develop'
Error al importar nómina y factura en lote
2018-11-07 19:15:54 -06:00
Mauricio Baeza 2d045af037 Error al importar nómina y factura en lote 2018-11-07 19:14:54 -06:00
Mauricio Baeza 4660e1d4e0 Merge branch 'develop'
Error: Consulta de  estatus en el SAT
2018-11-06 22:57:06 -06:00
Mauricio Baeza 68ed8ee0db Error: Consulta de estatus en el SAT 2018-11-06 22:56:43 -06:00
Mauricio Baeza 47ed1cb72e Separar documentación 2018-10-31 17:15:53 -06:00
Mauricio Baeza dc8aeaebba Merge branch 'develop'
Mejora: Permitir importar CFDI 3.2
2018-10-30 16:37:15 -06:00
Mauricio Baeza d2dc80a0c9 Actualizar version 1.23.0 2018-10-30 16:25:17 -06:00
Mauricio Baeza e83281bdee Mejora: Se importan CFDI 3.2 2018-10-30 16:21:00 -06:00
Mauricio Baeza 0bddc189b4 Merge branch 'develop'
Mejora al generar factura en lote
2018-10-27 01:15:42 -05:00
Mauricio Baeza c2c8a10dec Mejora al generar factura en lote 2018-10-27 01:15:20 -05:00
Mauricio Baeza 1dddbac0f2 Permitir cambiar descrición al facturar en lote 2018-10-25 14:59:22 -05:00
Mauricio Baeza bbaf709e0e Merge branch 'develop'
Error unicode
2018-10-24 00:02:08 -05:00
Mauricio Baeza c42bc817b7 Actualizar version 2018-10-23 23:57:36 -05:00
Mauricio Baeza ba91d28fbd Error unicode 2018-10-23 23:43:23 -05:00
Mauricio Baeza 2765958a23 Merge branch 'develop'
Error #307
2018-10-14 22:24:34 -05:00
Mauricio Baeza c319ee454e Actualizar version 2018-10-14 22:24:07 -05:00
Mauricio Baeza 9f919d77bc Error #307 2018-10-14 14:37:12 -05:00
Mauricio Baeza 2090aa743d Merge branch 'develop'
Error #287
Mejora - Facturas de pago con datos bancarios
2018-10-12 01:23:17 -05:00
Mauricio Baeza af5d526bad Error #287 2018-10-12 01:14:01 -05:00
Mauricio Baeza 4eb4cc8fa5 Error #287 2018-10-10 22:25:10 -05:00
Mauricio Baeza 4007923f84 Actualizar dpcumentación 2018-10-09 00:03:20 -05:00
Mauricio Baeza 4a5bf615c4 Cuentas de banco para clientes nuevos 2018-10-08 14:13:16 -05:00
Mauricio Baeza 63fc8e9a78 Merge branch 'develop'
Error #295
Cuentas de banco para clientes
2018-10-08 01:14:24 -05:00
Mauricio Baeza 4f34599a6f Cuentas de banco para clientes 2018-10-08 01:13:46 -05:00
Mauricio Baeza 5ac614e079 Error #295 2018-10-07 20:29:14 -05:00
Mauricio Baeza 0465b684f0 Mejora #292 2018-10-05 23:13:03 -05:00
Mauricio Baeza d70c35b4de Error #295 2018-10-04 23:25:52 -05:00
Mauricio Baeza 3cc85e2644 Error #295 2018-10-04 17:52:50 -05:00
Mauricio Baeza ae4c4b9355 Actualizar versiona a 1.20.0Error #295 2018-10-04 15:58:40 -05:00
Mauricio Baeza e7666432cb Error #295 2018-10-04 15:56:41 -05:00
Mauricio Baeza 425f2ee079 Merge branch 'develop'
Relacionar facturas v3.2
2018-10-03 23:40:52 -05:00
Mauricio Baeza a6edbaa56f Relacionar facturas v3.2 2018-10-03 23:40:18 -05:00
Mauricio Baeza db435a9b3d Filtrar por pagar facturas v3.2 2018-10-03 23:15:32 -05:00
Mauricio Baeza aee9a83dd2 Importar CFDI sin marcar como pagada 2018-10-03 20:51:26 -05:00
Mauricio Baeza acd8604e92 Merge branch 'develop'
Error #291
2018-10-03 15:23:17 -05:00
Mauricio Baeza eab8c3bb94 Error #291 2018-10-03 15:22:47 -05:00
Mauricio Baeza a15ddd3544 Error #291 2018-09-28 23:04:02 -05:00
Mauricio Baeza 23055b9af5 Error #291 2018-09-28 23:01:04 -05:00
Mauricio Baeza 71d773f999 Merge branch 'develop'
Mejora #280
Mejora #288
Error #290
2018-09-28 02:24:12 -05:00
Mauricio Baeza 65587eb207 Actualizar version y notas de lanzamiento 2018-09-28 02:23:01 -05:00
Mauricio Baeza d795069b38 Mejoras #280 #288 2018-09-28 02:17:17 -05:00
Mauricio Baeza 17a9b00cb5 Error #290 2018-09-27 19:12:33 -05:00
Mauricio Baeza 2e98d69685 Merge branch 'develop'
Error #282
2018-09-27 00:37:29 -05:00
Mauricio Baeza 0b73efaf9b Doc + Facturas en otras monedas 2018-09-27 00:31:36 -05:00
Mauricio Baeza a7d0339660 Error #282 2018-09-26 23:22:29 -05:00
Mauricio Baeza 135d469f3e Merge branch 'develop'
Soporte para facturas de pagos con documentos en otras monedas
2018-09-26 01:30:34 -05:00
Mauricio Baeza 43a50b833f Doc + Bancos y complemento de pagos 2018-09-26 01:26:23 -05:00
Mauricio Baeza 44cf4089f7 Mostrar moneda al timbrar factura nueva 2018-09-25 22:03:16 -05:00
Mauricio Baeza accd49d101 Error #278 2018-09-25 15:38:13 -05:00
Mauricio Baeza 65d68db2d7 Actualizar version a 1.17.0 2018-09-25 01:45:40 -05:00
Mauricio Baeza 73fa31abc8 Mejora #278 2018-09-25 01:36:24 -05:00
Mauricio Baeza 278bd06b72 Agregar tipo de cambio en facturas relacionadas otras monedas 2018-09-25 01:24:37 -05:00
Mauricio Baeza 12d26e01f9 Eliminar factura de pago cuando no esta timbrada 2018-09-23 22:36:16 -05:00
Mauricio Baeza 6d3625caf7 Doc Actualizar 2018-09-22 00:32:38 -05:00
Mauricio Baeza 760d33a389 Iniciar documentación 2018-09-20 20:50:13 -05:00
Mauricio Baeza 18b1880772 Merge branch 'develop'
Aactualizar versión 1.16.1
2018-09-18 10:58:04 -05:00
Mauricio Baeza 933068069c Actualizar versión 1.16.1 2018-09-18 10:57:50 -05:00
Mauricio Baeza 66111d9080 Merge branch 'develop'
Error #268
2018-09-18 10:52:34 -05:00
Mauricio Baeza 525394dbed Error #268 2018-09-18 10:35:07 -05:00
Mauricio Baeza 127ceceada Merge branch 'develop'
Se puede modidicar el saldo del cliente
Se muestra la cantidad de facturas de pago en los movimientos
2018-09-16 22:10:15 -05:00
Mauricio Baeza a05b370c33 Actualizar versión 2018-09-16 22:06:06 -05:00
Mauricio Baeza 8efe19fd24 Mejora - #262 2018-09-16 20:41:47 -05:00
Mauricio Baeza c8371a272f Mejora - #262 2018-09-16 01:17:18 -05:00
Mauricio Baeza 25cf581fcb Mejora - #248 2018-09-16 00:34:35 -05:00
Mauricio Baeza b6b5aa3447 Merge branch 'develop'
Fix # 257
2018-09-12 23:23:58 -05:00
Mauricio Baeza 0379fd6a6a Fix - #259 2018-09-12 22:19:51 -05:00
Mauricio Baeza 30fab23c0d Fix - #257 2018-09-12 17:59:17 -05:00
Mauricio Baeza b8f5dbd421 Fix - #260 2018-09-12 17:42:52 -05:00
Mauricio Baeza 63b9d6729b Fix - #259 2018-09-12 15:41:34 -05:00
Mauricio Baeza 5e6d86cb6b Fix - #257 2018-09-12 13:35:03 -05:00
Mauricio Baeza b0de7655cc Merge branch 'develop'
Personalizar plantilla para factura de pago
2018-09-10 23:08:38 -05:00
Mauricio Baeza 12297b9479 Personalizar plantilla para factura de pago 2018-09-10 23:07:52 -05:00
Mauricio Baeza dea511d161 Merge branch 'develop'
Fix - Al agregar cuenta de banco
2018-09-10 17:35:28 -05:00
Mauricio Baeza faa07f937f Fix - Al agregar cuenta de banco 2018-09-10 17:34:54 -05:00
Mauricio Baeza 9081d54865 Merge branch 'develop'
Cancelar factura de pago
2018-09-10 00:18:39 -05:00
Mauricio Baeza ca4810bd3d Pasar RFC al migrar tablas 2018-09-10 00:17:17 -05:00
Mauricio Baeza aece36905d Actualizar saldo de cuenta al cancelar movimiento 2018-09-10 00:05:24 -05:00
Mauricio Baeza 1ee3f81dcc Evitar cancelar movimiento con factura de pago 2018-09-10 00:00:52 -05:00
Mauricio Baeza 0ec7989c75 Cancelar CFDI de pago 2018-09-07 00:08:16 -05:00
Mauricio Baeza e5a389a9dd Fix #256 2018-09-06 18:15:54 -05:00
Mauricio Baeza dd0585853a Fix #251 2018-09-05 23:47:55 -05:00
Mauricio Baeza 3dd73c1467 Fix #249 2018-09-05 22:49:53 -05:00
Mauricio Baeza f0ab9246e0 Merge branch 'develop'
Fix - al migrar tablas
2018-09-03 02:18:29 -05:00
Mauricio Baeza 80b87348f0 Fix - al migrar tablas 2018-09-03 02:18:07 -05:00
Mauricio Baeza 8de2b20dcf Merge branch 'develop'
Soporte para Factura de pagos
2018-09-03 00:55:28 -05:00
Mauricio Baeza 6c0fc15053 Factura de pago, establecer serie y folio inicial 2018-09-02 22:33:53 -05:00
Mauricio Baeza e8f27904d9 Factura de pago, envío por correo 2018-09-02 20:55:47 -05:00
Mauricio Baeza d1b94cab57 Fix - Al cambiar cuenta de banco 2018-09-01 10:47:03 -05:00
Mauricio Baeza 31c6261183 Actualizar readme 2018-08-30 23:37:10 -05:00
Mauricio Baeza 118fa41d9b Configurar valores predeterminados para CFDI de pagos 2018-08-30 20:49:45 -05:00
Mauricio Baeza b202827ee0 Merge branch 'pagos' into develop
Soporte para complemento de pagos
2018-08-30 19:54:46 -05:00
Mauricio Baeza fd75da65fc Generate PDF from cfdi pay 2018-08-30 19:24:33 -05:00
Mauricio Baeza 9dc2c72de7 Add template cfdi pay 2018-08-30 11:25:40 -05:00
Mauricio Baeza fdbfbb2bc0 Stamp XML cfdi pay 2018-08-30 00:13:12 -05:00
Mauricio Baeza 6a724ac845 Generate XML cfdi pay 2018-08-28 01:02:35 -05:00
Mauricio Baeza 282f31497f Save cfdi pay 2018-08-27 00:53:52 -05:00
Mauricio Baeza 54c01de410 Add new fields to cfdipagos 2018-08-24 23:04:10 -05:00
Mauricio Baeza 6339e11c37 Get related invoice 2018-08-24 00:52:59 -05:00
Mauricio Baeza 7896d66448 UI para complemento de pago 2018-08-23 00:55:45 -05:00
Mauricio Baeza 0f02411de6 Merge branch 'update' into develop
Actualizar webix y lokyjs
2018-08-22 22:12:47 -05:00
Mauricio Baeza c438e7dc1d Actualizar webix y lokyjs 2018-08-22 00:01:07 -05:00
Mauricio Baeza 4608246b7d Merge branch 'develop'
Quitar columnas en tabla facturaspagos
Actualizar version y lista de cambios
2018-08-21 18:52:55 -05:00
Mauricio Baeza ea18996111 Actualizar versión y lista de cambios 2018-08-21 18:52:36 -05:00
Mauricio Baeza 7c00839b1f Fix - Quitar columna 'cancelado' en tabla 'facturaspagos' 2018-08-21 18:49:53 -05:00
Mauricio Baeza 94240f2356 Merge branch 'develop'
Error al cerrar plantilla
2018-08-09 15:51:34 -05:00
Mauricio Baeza 4ab3b22f29 Error al cerrar plantilla 2018-08-09 15:51:11 -05:00
Mauricio Baeza 88085bfa06 Fix - redondeo en retenciones 2018-08-03 23:01:21 -05:00
Mauricio Baeza 3163fef0d5 Merge branch 'develop'
Cambio en consulta de timbres
2018-07-25 16:28:22 -05:00
Mauricio Baeza cb6e4e21cf Cambio en consulta de timbres 2018-07-25 16:27:53 -05:00
Mauricio Baeza 32ec443a19 Merge branch 'develop'
Precios con cuatro decimales. Ticket #229
2018-07-10 23:37:35 -05:00
Mauricio Baeza c85af83275 Precios con cuatro decimales 2018-07-10 23:34:32 -05:00
Mauricio Baeza 64caf4f415 Merge branch 'develop'
Actualizar versión
2018-07-08 23:46:21 -05:00
Mauricio Baeza 064a65c0ae Actualizar version 2018-07-08 23:45:39 -05:00
Mauricio Baeza 13836add29 Merge branch 'develop'
Fix - Ticket #231
2018-07-08 23:43:19 -05:00
Mauricio Baeza 0bf0769ad7 Fix - Ticket #231 2018-07-08 23:41:13 -05:00
Mauricio Baeza f3309429e6 Merge branch 'develop'
Actualizar versión
2018-07-05 23:56:08 -05:00
Mauricio Baeza 3ce31258e2 Actualizar versión 2018-07-05 23:55:53 -05:00
Mauricio Baeza f9e4bced15 Merge branch 'develop'
Fix - Ticket #230
2018-07-05 23:53:02 -05:00
Mauricio Baeza a04f92fab8 Fix - Ticket #230 2018-07-05 23:52:09 -05:00
Mauricio Baeza c3d92ff45e Merge branch 'develop'
Fix - Al mostrar el título
2018-06-25 22:58:03 -05:00
Mauricio Baeza a8405a98fb Fix - Al mostrar el título 2018-06-25 22:56:02 -05:00
112 changed files with 44324 additions and 51800 deletions

15
.gitignore vendored
View File

@ -2,6 +2,7 @@
__pycache__/
*.py[cod]
*$py.class
Pipfile*
# Django stuff:
*.log
@ -14,7 +15,17 @@ source/media
# Sphinx documentation
*.xlsx
docs/
bk/
source/docs/
site/
vedev/
# Virtualenv
.env/
virtual/
env
docs/build
cache/
credenciales.conf
*.sqlite
@ -22,4 +33,6 @@ credenciales.conf
*.service
*.orig
rfc.db
Dockerfile
chuletas/

View File

@ -1,3 +1,741 @@
v 2.3.2 [10-Abr-2024]
- Fix: En las mercancias en la Carta Porte al generar el PDF.
v 2.3.1 [02-Abr-2024]
- Fix: En la cantidad de la mercancia en la Carta Porte.
v 2.3.0 [01-Abr-2024]
- Mejora: Soporte para complemento Carta Porte 3.0
- **IMPORTANTE**: Aunque no lo uses, esto afecta al JS de facturación, por
lo que tienes que forzar el refresco (CTRL+F5) si tienes algún problema.
v 2.2.0 [24-Ene-2024]
- Mejora: Soporte para complemento Comercio Exterior 2.0
- **IMPORTANTE**: Aunque no lo uses, esto afecta al JS de facturación, por
lo que tienes que forzar el refresco (CTRL+F5) si tienes algún problema.
v 2.1.0 [26-Dic-2023]
- Mejora: Se agrega filtro por día en facturas.
v 2.0.9 [20-Dic-2023]
- Fix: Issue 98 y 107
v 2.0.8 [30-Oct-2023]
---------------------
- Fix: Permitir generar CFDI de egreso para facturas globales sin datos globales.
- Fix: Permitir cambiar la zona horaria para cuando se usa en servidor.
Es necesario hacer una migración:
```
cd /opt/empresa-libre
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m -r RFC
```
v 2.0.7 [06-Ju1-2023]
---------------------
- Fix: En tasa de retención de un Resico a una Persona Moral.
v 2.0.6 [14-Jun-2023]
---------------------
- Fix: Al generar complementos de pago con facturas con retención de impuestos.
v 2.0.5 [05-Jun-2023]
---------------------
- Fix: Al generar complementos de pago con facturas con varios impuestos.
- Fix: ticket #103, hay que usar {receptor.correo_facturas} y {receptor.telefonos}
v 2.0.2 [01-Abr-2023]
---------------------
- Fix: Obtener la clave del sat al facturar por lote.
v 2.0.1 [29-Mar-2023]
---------------------
- Fix ticket #97
Es necesario hacer una migración:
```
cd /opt/empresa-libre
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m -r RFC
```
v 2.0.0 [08-Ene-2023]
----------------------
- Liberamos para todos la versión CFDI 4.0
- **IMPORTANTE** NO intentes timbrar si **antes** no has validado en nuestro demo que puedes timbrar tus CFDIs habituales.
* IMPORTANTE:
Es necesario hacer una migración:
```
cd /opt/empresa-libre
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m -r RFC
```
Y reiniciar todo. IMPORTANTE: dependiendo desde que versión actualices, tal vez debas de hacer algún prodecimiento extra. Siempre revisa este historial.
v 2.0.0 [31-Mar-2022]
----------------------
- Primera versión de timbrado con CFDI4
- **IMPORTANTE** NO intentes timbrar si **antes** no has validado en nuestro demo que puedes timbrar tus CFDIs habituales.
v 1.47.0 [28-Mar-2022]
----------------------
- Mejora: Soporte basico para complemento Comercio Exterior.
v 1.46.5 [10-Mar-2022]
----------------------
- Error: Al timbrar nómina con Comercio Digital
v 1.46.4 [18-Feb-2022]
----------------------
- Error: Issue #54
v 1.46.3 [15-Feb-2022]
----------------------
- Error: Issue #53
v 1.46.2 [31-Ene-2022]
----------------------
- Error: Al generar Carta Porte sin remolque.
- Error: Al cancelar con Finkok.
v 1.46.1 [29-Ene-2022]
----------------------
- Error: Issue #49
- Mejora: Agregar validación para distancia en origen de Carta Porte.
v 1.46.0 [27-Ene-2022]
----------------------
- Mejora: Issue #45
- Mejora: Agregar tipos de persimos SCT para Carta Porte
- Mejora: Buscar estado y municipio por CP en Carta Porte
v 1.45.4 [25-Ene-2022]
----------------------
- Error: Al timbrar carta porte.
- Error: Al cancelar con Comercio Digital.
- Error: Issue #42
- Mejora: Issue #44
* IMPORTANTE: Es necesario subir de nuevo tus certificados de sello, **solo** si timbras con Comercio Digital.
v 1.45.3 [23-Ene-2022]
----------------------
- Error: El enviar por correo CFDI de pago. Ticket #40
v 1.45.2 [21-Ene-2022]
----------------------
- Error: Al cancelar un CFDI
v 1.45.1 [20-Ene-2022]
----------------------
- Error: Al enviar correos con la nueva configuración
* IMPORTANTE: Revisa tu configuración de correo para verificar que todo funcione.
v 1.45.0 [20-Ene-2022]
----------------------
- Importar Carta Porte desde archivo JSON
v 1.44.2 [19-Ene-2022]
----------------------
- Agregar opción STARTTLS que requieren algunos servidores de correo
* IMPORTANTE: Revisa tu configuración de correo para verificar si tienes que usar esta opción.
v 1.44.1 [19-Ene-2022]
----------------------
- Correciones en generación de Carta Porte v2.0
- Plantilla para representación impresa de Carta Porte v2.0
v 1.44.0 [10-Ene-2022]
----------------------
- Soporte para Carta Porte v2 con CFDI 3.3
- Soporte para el nuevo esquema de cancelación del SAT
* IMPORTANTE:
Es necesario hacer una migración:
```
cd /opt/empresa-libre
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m -r RFC
```
v 1.43.0 [12-Dic-2021]
----------------------
- Soporte para entradas de almacen.
- Soporte para multi almacen.
- Soporte para regenerar un ticket.
- Soporte para movimientos entre almacenes
- Consulta en SAT para estatus de nómina
* IMPORTANTE:
Instalar nuevo requerimiento:
```
pip install segno
```
Es necesario hacer una migración:
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m -r RFC
```
v 1.42.2 [14-Sep-2021]
----------------------
- Los productos pueden no llevar ningún impuesto.
v 1.42.1 [01-Jun-2021]
----------------------
- Error - Ticket #5
v 1.42.0 [24-May-2021]
----------------------
- Opción para que solo un admin pueda cancelar.
v 1.41.4 [13-Abr-2021]
----------------------
- Error - Ticket #4
v 1.41.3 [12-Feb-2021]
----------------------
- Error - Ticket #3
v 1.41.2 [12-Feb-2021]
----------------------
- Error - Ticket #2
v 1.41.1 [11-Feb-2021]
----------------------
- Error - Ticket #1
v 1.41.0 [10-Feb-2021]
----------------------
- Importar clientes desde archivo CSV
v 1.40.1 [09-Feb-2021]
----------------------
- Fix #422
v 1.40.0 [05-ene-2021]
----------------------
- Error: Al parsear XML en Python 3.9+
- Mejora: Agregar versión de Empresa Libre a plantilla.
- Mejora: Sellado en memoria
- Mejora: Se agrega un segundo PAC y se refactoriza el timbrado.
* **IMPORTANTE**
Es necesario seguir una serie de pasos **obligatorios** para migrar a esta
versión, **no continues hasta seguir paso a paso** estas instrucciones.
**Antes** de comenzar ten a la mano tus certificados de sello para timbrar, es
necesario subirlos de nuevo. **NO actualices si no tienes tus certificados**
con su respectiva contraseña, te quedarás sin poder timbrar.
Estas instrucciones solamente aplican para la maquina virtual con Ubuntu Server,
la ultima y única versión sobre la que se dará soporte.
1. Entra a la parte administrativa y toma de tus credenciales de timbrado en el
menú "Emisor" ficha "Otros Datos", usuario y token de timbrado.
1. Agregar nuevos requerimientos `sudo apt install pkgconf libxml2-dev libxmlsec1-dev libxmlsec1-openssl`
1. Agregar nuevo requerimiento `pip install --user xmlsec`
1. Entrar a la carpeta del sistema: `/opt/empresa-libre`
1. Actualizar `git pull origin master`
1. Entrar a `source/app/controllers/pacs/comerciodigital` y copiar `conf.py.example` a `conf.py`
1. Entrar a `source/app/controllers/pacs/finkok` y copiar `conf.py.example` a `conf.py`
1. Agregar la variable `TOKEN = ''` al archivo `source/app/conf.py` mira el archivo de ejemplo en el mismo directorio.
1. Reiniciar el servicio: `sudo systemctl restart empresalibre`
1. Si no ves los cambios descritos a continuación, fuerza el refresco de tu navegador, generalmente con **CTRL+F5**
1. Sube de nuevo tus certificados en el menú "Emisor" ficha "Certificado".
1. Ve al menú "Opciones", ficha "Otros".
1. Selecciona tu PAC, si tu usuario es un correo electrónico, invariablemente
debes seleccionar Finkok. Si tienes duda ponte en contacto con nosotros.
1. Establece las credenciales del punto 1.
1. Guarda los datos.
v 1.39.1 [17-sep-2020]
----------------------
- Error: Esquema para complemento IEDU
v 1.39.0 [25-ago-2020]
----------------------
- Mejora: Consulta de las facturas de pago en el SAT
- Mejora: Mostrar totales en nómina
- Mejora: Mostrar totales por cantidad al facturar
- Mejora: Validar líneas con importe cero antes de facturar
- Error: Validaciones de namespace en CFDI de nómina por parte del PAC
v 1.38.1 [30-mar-2020]
----------------------
- Error: En nómina al timbrar asimilados
v 1.38.0 [08-mar-2020]
----------------------
- Mejora: Factura global por ticket o nota
- Error: Al generar algunos PDFs
v 1.37.0 [02-mar-2020]
----------------------
- Mejora: Soporte para complemento Leyendas Fiscales
* IMPORTANTE:
Es necesario hacer una migración, y agregar los campos necesarios para mostrar
las leyendas, mira la carpeta pública con la plantilla de ejemplo.
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m -r RFC
```
v 1.36.0 [25-feb-2020]
----------------------
- Mejora: Permitir ver a usuarios todos los documentos
v 1.35.0 [24-feb-2020]
----------------------
- Mejora: Filtrado de documentos por sucursal
v 1.34.1 [09-feb-2020]
----------------------
- Error: Al timbrar nómina de asimilados
v 1.34.0 [29-ene-2020]
----------------------
- Error: Al timbrar nómina
v 1.33.2 [27-ene-2020]
----------------------
- Se actualizan métodos de pago en catálogos del SAT
* IMPORTANTE:
Es necesario actualizar los catálogos del SAT
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -us
```
v 1.33.0 [22-ene-2020]
----------------------
- Mejora: Cambio del mensaje para cuando se intenta dar de alta un cliente ya existente.
- Mejora: Solo los admins pueden ver la nómina.
- Se agrega un segundo PAC
- Se actualizan los catálogos del SAT
* IMPORTANTE:
Es necesario actualizar los catálogos del SAT
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -us
```
v 1.32.0 [05-ene-2020]
----------------------
- Mejora: Recuperar facturas no aceptadas para cancelación por el receptor
v 1.31.2 [28-oct-2019]
----------------------
- Error: Al generar PDF con tags en las series
v 1.31.1 [28-ago-2019]
----------------------
- Error: Al agregar nuevo impuesto #369
v 1.31.0 [23-abr-2019]
----------------------
- Error: Validar cantidad o valor unitario cero en tickets
- Mejora: Envío de nómina por correo al empleado
v 1.30.0 [24-mar-2019]
----------------------
- Mejora: Se actualizan los catálogos de Nómina
* IMPORTANTE:
Es necesario realizar una migración, después de actualizar.
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m
```
v 1.29.0 [08-mar-2019]
----------------------
- Error: Al mostrar detalle en facturas importadas #343
- Mejora: Editar la descripción de un movimiento bancario.
v 1.28.2 [04-mar-2019]
----------------------
- Error: Al enviar facturas de pago
v 1.28.1 [04-mar-2019]
----------------------
- Error: Al buscar facturas por fechas
v 1.28.0 [17-feb-2019]
----------------------
- Mejora: Manejo de empaques para mensajeria
- Mejora: Usar concepto personalizado en deducciones de nómina 004 Otros
- Mejora: Búsqueda en notas
- Mejora: Soporte para el complemento de Divisas
- Mejora: Descarga de nómina en lote
* IMPORTANTE:
Es necesario realizar una migración, después de actualizar.
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m
```
Es necesario agregar un nuevo requerimiento.
```
sudo pip install cryptography
```
**IMPORTANTE** Si envias tus facturas por correo directamente, es necesario
volver a capturar la contraseña de tu servidor de correo y guardar los datos
nuevamente.
v 1.27.1 [23-ene-2019]
----------------------
- Error: Al cancelar nómina
v 1.27.0 [17-ene-2019]
----------------------
- Mejora: Permitir capturar folio manualmente
v 1.26.1 [16-ene-2019]
----------------------
- Error: Guardar logos de emisor
v 1.26.0 [15-ene-2019]
----------------------
- Mejora: Generar PDF desde plantilla JSON
v 1.25.0 [07-nov-2018]
----------------------
- Fix: Al importar días de pago en nómina
- Fix: Al importar descripción en factura en lote
v 1.24.0 [06-nov-2018]
----------------------
- Fix: Consulta estatus SAT
v 1.23.0 [30-oct-2018]
----------------------
- Mejora: Permitir importar CFDI 3.2
v 1.22.0 [25-oct-2018]
----------------------
- Mejora: Permitir cambiar descripción al facturar en lote
v 1.21.2 [23-oct-2018]
----------------------
- Error unicode
v 1.21.1 [14-oct-2018]
----------------------
- Error #307
v 1.21.0 [12-oct-2018]
----------------------
- Error #287
- Mejora: Complemento de pago con datos de cuentas
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar.
v 1.20.0 [08-oct-2018]
----------------------
- Error #295
- Mejora: Cuentas de banco para clientes
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar.
v 1.19.1 [03-oct-2018]
----------------------
- Error #291
- Error al generar PDF de factura de pago con relacionados sin serie
- Error al relacionar facturas versión 3.2
v 1.19.0 [28-sep-2018]
----------------------
- Mejora #280
- Mejora #288
- Error #290
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar la rama principal.
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m
```
v 1.18.0 [27-sep-2018]
----------------------
- Fix #282 Factura de pago en otras monedas
v 1.17.0 [25-sep-2018]
----------------------
- Fix - Al generar factura de pago con documentos relacionados en otras monedas
- Fix - Al generar factura de pago sin serie en documentos relacionados
- Fix #278
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar la rama principal.
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m
```
v 1.16.1 [18-sep-2018]
----------------------
- Error https://gitlab.com/mauriciobaeza/empresa-libre/issues/268
- IMPORTANTE: Actualizar si usas cuatro decimales en impuestos
v 1.16.0 [16-sep-2018]
----------------------
- Se puede editar el saldo de un cliente
- Se muestra la cantidad de facturas de pago en los movimientos
v 1.15.0 [12-sep-2018]
----------------------
- Se pueden mover las facturas con doble clic en los movimientos de banco.
- Fix - Al sumar las facturas en los depósitos
- Fix - Al importar los pedimentos en facturas por lotes
- Fix - Al guardar los datos del emisor
v 1.14.0 [10-sep-2018]
----------------------
- Personalizar plantilla para factura de pago
- Fix - Mostrar serie y folio capturado para factura de pago
- Fix - Agregar nueva cuenta de banco
v 1.13.0 [10-sep-2018]
----------------------
- Cancelar factura de pago
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar la rama principal.
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m
```
v 1.12.0 [31-ago-2018]
----------------------
- Soporte para facturas (complemento) de pago.
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar la rama principal.
```
git pull origin master
cd source/app/models
python main.py -bk
python main.py -m
```
v 1.11.1 [21-ago-2018]
----------------------
- Fix - Quitar columna en tabla facturaspagos.
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar la rama principal.
```
git pull origin master
cd source/app/models
python main.py -m
```
v 1.11.0 [25-jul-2018]
----------------------
- Se cambia la forma de consultar los folios restantes. Es indispensable actualizar a esta versión para ver tus timbres restantes.
v 1.10.0 [10-jul-2018]
----------------------
- Ahora se pueden manejar precios con cuatro decimales.
v 1.9.3 [08-jul-2018]
---------------------
- Fix: Al refacturar conceptos con descuento
v 1.9.2 [05-jul-2018]
---------------------
- Fix: Al generar el reporte de facturas en PDF
v 1.9.1 [25-jun-2018]
---------------------
- Fix: Al mostrar el título de la aplicación
- Se agrega el registro de acción al borrar una factura
v 1.9.0 [18-jun-2018]
---------------------
- Se agrega la vista del detalle de facturas

View File

@ -13,9 +13,3 @@
* Propon nuevas funcionalidades
* Difunde Empresa Libre
### Prioridades
1. [X] Darle continuidad a la facturación de los clientes
2. Cubrir todas las funcionalidades que cubre ahora Factura Libre
3. Agregar nuevas funcionalidades

View File

@ -10,22 +10,51 @@ Este proyecto está en continuo desarrollo, contratar un esquema de soporte,
nos ayuda a continuar su desarrollo. Ponte en contacto con nosotros para
contratar: administracion ARROBA empresalibre.net
#### Ahora también puede aportar con criptomonedas:
### Requerimientos:
G1: `A5DdXxCKPw3QKWVdDVs7CzkNugNUW1sHu5zDJFWxCU2h`
BCH: `qztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d`
## Requerimientos:
* Servidor web, recomendado Nginx
* uwsgi
* python3
* python 3.8
* xsltproc
* openssl
* xmlsec
* Ubuntu 20.04
```
apt install pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl xsltproc
```
Debería de funcionar con cualquier combinación servidor-wsgi que soporte
aplicaciones Python.
El sistema tiene soporte para tres bases de datos: SQLite, MySQL y PostgreSQL
(recomendado), debes de instalar el servidor de la base de datos y sus drivers
respectivos, excepto SQLite que es nativo en Python.
El sistema tiene soporte solo para PostgreSQL, debes de instalar el servidor de
la base de datos y su driver respectivo.
## Configuración para desarrollo local
* Crea un entorno virtual con python 3.8 y actívalo. Por ejemplo con virtualenv:
virtualenv .venv
source .venv/bin/activate
* Instala las dependencias
pip install -r requirements.txt
* Copia y ajusta algunos archivos necesarios.
- `source/app/conf.py`
- `source/app/controllers/pacs/comerciodigital/conf.py.example`
- `source/app/controllers/pacs/finkok/conf.py.example`
* Finalmente ejecutamos la aplicación. Para esto vamos a necesitar un servidor
wsgi como uwsgi:
pip install uwsgi
cd source/app
uwsgi main_debug.ini
* Ahora puedes ver la aplicación en http://localhost:8000

3
TODO.md Normal file
View File

@ -0,0 +1,3 @@
[ ] Permitir más de un remolque en la Carta Porte
[ ] Campos de captura de Comercio Exterior
[ ] Representación impresa de Comercio Exterior

View File

@ -1 +1 @@
1.9.0
2.3.2

View File

@ -1,15 +1,17 @@
falcon
falcon==1.4.1
falcon-multipart
Beaker
Mako
peewee==2.10.2
Click
logbook
bcrypt
python-dateutil
zeep
chardet
pyqrcode
pypng
reportlab
psycopg2-binary
cryptography==3.4.8
xmlsec
segno
# python-escpos

View File

@ -2,23 +2,20 @@
DEBUG = False
MV = True
MV = False
# ~ Es la contraseña predeterminada de los usuarios admin y superadmin al crear
# ~ una nueva base de datos, personaliza por la que quieras.
DEFAULT_PASSWORD = 'salgueiro3.3'
TITLE_APP = 'Empresa Libre'
#~ Establece una ruta accesible para el servidor web
LOG_PATH = '/home/empresa/.opt/empresa-libre.log'
LOG_PATH = '/var/log/empresalibre/empresa-libre.log'
# ~ Establece los valores para sincronizar los backups de la base de datos
# ~ por ejemplo
# ~ SEAFILE_SERVER = {
# ~ 'URL': 'https://tu_servidor_seafile',
# ~ 'USER': 'tu_usuario',
# ~ 'PASS': 'tu_contraseña',
# ~ 'REPO': 'id_repo',
# ~ }
SEAFILE_SERVER = {}
# ~ Establece un token personalizado para encriptar las claves
# ~ from secrets import token_hex
# ~ token_hex(32)
# ~ IMPORTANTE: Cada vez que cambies este valor, debes de subir de nuevo
# ~ tus certificados
TOKEN = ''

View File

@ -1,25 +1,47 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# ~ Empresa Libre
# ~ Copyright (C) 2016-2018 Mauricio Baeza Servin (web@correolibre.net)
# ~
# ~ This program is free software: you can redistribute it and/or modify
# ~ it under the terms of the GNU General Public License as published by
# ~ the Free Software Foundation, either version 3 of the License, or
# ~ (at your option) any later version.
# ~
# ~ This program is distributed in the hope that it will be useful,
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# ~ GNU General Public License for more details.
# ~
# ~ You should have received a copy of the GNU General Public License
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
import datetime
from xml.etree import ElementTree as ET
from xml.dom.minidom import parseString
from dateutil import parser
from logbook import Logger
#~ from settings import DEBUG
log = Logger('XML')
CFDI_ACTUAL = 'cfdi33'
CFDI_ACTUAL = 'cfdi40'
NOMINA_ACTUAL = 'nomina12'
PUBLIC = 'PUBLICO EN GENERAL'
CFDI_EGRESO = 'E'
DEFAULT = {
'exportacion': '01',
}
SAT = {
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'cfdi32': {
'version': '3.2',
'cfdi40': {
'version': '4.0',
'prefix': 'cfdi',
'xmlns': 'http://www.sat.gob.mx/cfd/3',
'schema': 'http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd',
'xmlns': 'http://www.sat.gob.mx/cfd/4',
'schema': 'http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd',
},
'cfdi33': {
'version': '3.3',
@ -27,17 +49,23 @@ SAT = {
'xmlns': 'http://www.sat.gob.mx/cfd/3',
'schema': 'http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv33.xsd',
},
'cfdi32': {
'version': '3.2',
'prefix': 'cfdi',
'xmlns': 'http://www.sat.gob.mx/cfd/3',
'schema': 'http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd',
},
'nomina11': {
'version': '1.1',
'prefix': 'nomina',
'xmlns': 'http://www.sat.gob.mx/nomina',
'schema': 'http://www.sat.gob.mx/nomina http://www.sat.gob.mx/sitio_internet/cfd/nomina/nomina11.xsd',
'schema': ' http://www.sat.gob.mx/nomina http://www.sat.gob.mx/sitio_internet/cfd/nomina/nomina11.xsd',
},
'nomina': {
'version': '1.2',
'prefix': 'nomina12',
'xmlns': 'http://www.sat.gob.mx/nomina12',
'schema': 'http://www.sat.gob.mx/nomina12 http://www.sat.gob.mx/sitio_internet/cfd/nomina/nomina12.xsd',
'schema': ' http://www.sat.gob.mx/nomina12 http://www.sat.gob.mx/sitio_internet/cfd/nomina/nomina12.xsd',
},
'locales': {
'version': '1.0',
@ -62,8 +90,38 @@ SAT = {
'version': '1.0',
'prefix': 'iedu',
'xmlns': 'http://www.sat.gob.mx/iedu',
'schema': ' http://www.sat.gob.mx/iedu http://www.sat.gob.mx/sitio_internet/cfd/ine/iedu.xsd',
'schema': ' http://www.sat.gob.mx/iedu http://www.sat.gob.mx/sitio_internet/cfd/iedu/iedu.xsd',
},
'pagos': {
'version': '2.0',
'prefix': 'pago20',
'xmlns': 'http://www.sat.gob.mx/Pagos20',
'schema': ' http://www.sat.gob.mx/Pagos20 http://www.sat.gob.mx/sitio_internet/cfd/Pagos/Pagos20.xsd',
},
'divisas': {
'version': '1.0',
'prefix': 'divisas',
'xmlns': 'http://www.sat.gob.mx/divisas',
'schema': ' http://www.sat.gob.mx/divisas http://www.sat.gob.mx/sitio_internet/cfd/divisas/divisas.xsd',
},
'leyendas': {
'version': '1.0',
'prefix': 'leyendasFisc',
'xmlns': 'http://www.sat.gob.mx/leyendasFiscales',
'schema': ' http://www.sat.gob.mx/leyendasFiscales http://www.sat.gob.mx/sitio_internet/cfd/leyendasFiscales/leyendasFisc.xsd',
},
'cartaporte': {
'version': '3.0',
'prefix': 'cartaporte30',
'xmlns': 'http://www.sat.gob.mx/CartaPorte30',
'schema': ' http://www.sat.gob.mx/CartaPorte30 http://www.sat.gob.mx/sitio_internet/cfd/CartaPorte/CartaPorte30.xsd',
},
'comercioe': {
'version': '2.0',
'prefix': 'cce20',
'xmlns': 'http://www.sat.gob.mx/ComercioExterior20',
'schema': ' http://www.sat.gob.mx/ComercioExterior20 http://www.sat.gob.mx/sitio_internet/cfd/ComercioExterior20/ComercioExterior20.xsd',
}
}
@ -79,7 +137,14 @@ class CFDI(object):
self._donativo = False
self._ine = False
self._edu = False
self._pagos = False
self._is_nomina = False
self._leyendas = False
self._carta_porte = False
self._comercio_exterior = False
self._divisas = ''
self._tipo_de_comprobante = ''
self._exportacion = DEFAULT['exportacion']
self.error = ''
def _now(self):
@ -90,6 +155,8 @@ class CFDI(object):
return ''
self._comprobante(datos['comprobante'])
if 'global' in datos:
self._informacion_global(datos['global'])
self._relacionados(datos['relacionados'])
self._emisor(datos['emisor'])
self._receptor(datos['receptor'])
@ -101,13 +168,14 @@ class CFDI(object):
if 'nomina' in datos:
self._nomina(datos['nomina'])
#~ if 'complementos' in datos:
#~ self._complementos(datos['complementos'])
return self._to_pretty_xml(ET.tostring(self._cfdi, encoding='utf-8'))
xml = self._to_pretty_xml(ET.tostring(self._cfdi, encoding='utf-8'))
def add_sello(self, sello):
return xml
def add_sello(self, sello, cert_txt):
self._cfdi.attrib['Sello'] = sello
self._cfdi.attrib['Certificado'] = cert_txt
return self._to_pretty_xml(ET.tostring(self._cfdi, encoding='utf-8'))
def _to_pretty_xml(self, source):
@ -129,6 +197,14 @@ class CFDI(object):
if datos['complementos']:
if 'ine' in datos['complementos']:
self._ine = True
self._pagos = bool(datos['complementos'].get('pagos', False))
self._leyendas = bool(datos['complementos'].get('leyendas', False))
self._carta_porte = bool(datos['complementos'].get('cartaporte', False))
self._comercio_exterior = bool(datos['complementos'].get('comercioe', False))
if self._comercio_exterior:
self._exportacion = datos['complementos']['comercioe'].pop('Exportacion')
self._divisas = datos['comprobante'].pop('divisas', '')
if 'nomina' in datos:
self._is_nomina = True
@ -168,15 +244,46 @@ class CFDI(object):
attributes[name] = SAT['edu']['xmlns']
schema_edu = SAT['edu']['schema']
schema_divisas = ''
if self._divisas:
name = 'xmlns:{}'.format(SAT['divisas']['prefix'])
attributes[name] = SAT['divisas']['xmlns']
schema_divisas = SAT['divisas']['schema']
schema_nomina = ''
if self._is_nomina:
name = 'xmlns:{}'.format(SAT['nomina']['prefix'])
attributes[name] = SAT['nomina']['xmlns']
schema_nomina = SAT['nomina']['schema']
schema_pagos = ''
if self._pagos:
name = 'xmlns:{}'.format(SAT['pagos']['prefix'])
attributes[name] = SAT['pagos']['xmlns']
schema_pagos = SAT['pagos']['schema']
schema_leyendas = ''
if self._leyendas:
name = 'xmlns:{}'.format(SAT['leyendas']['prefix'])
attributes[name] = SAT['leyendas']['xmlns']
schema_leyendas = SAT['leyendas']['schema']
schema_carta_porte = ''
if self._carta_porte:
name = 'xmlns:{}'.format(SAT['cartaporte']['prefix'])
attributes[name] = SAT['cartaporte']['xmlns']
schema_carta_porte = SAT['cartaporte']['schema']
schema_comercioe = ''
if self._comercio_exterior:
name = 'xmlns:{}'.format(SAT['comercioe']['prefix'])
attributes[name] = SAT['comercioe']['xmlns']
schema_carta_porte = SAT['comercioe']['schema']
attributes['xsi:schemaLocation'] = self._sat_cfdi['schema'] + \
schema_locales + schema_donativo + schema_ine + schema_edu + \
schema_nomina
schema_divisas + schema_nomina + schema_pagos + schema_leyendas + \
schema_carta_porte + schema_comercioe
attributes.update(datos)
if not 'Version' in attributes:
@ -184,9 +291,23 @@ class CFDI(object):
if not 'Fecha' in attributes:
attributes['Fecha'] = self._now()
# ~ cfdi4
if not 'Exportacion' in attributes:
attributes['Exportacion'] = self._exportacion
self._tipo_de_comprobante = attributes['TipoDeComprobante']
self._cfdi = ET.Element('{}:Comprobante'.format(self._pre), attributes)
return
def _informacion_global(self, datos):
if not datos:
return
node_name = '{}:InformacionGlobal'.format(self._pre)
node = ET.SubElement(self._cfdi, node_name, datos)
return
def _relacionados(self, datos):
if not datos or not datos['tipo'] or not datos['cfdis']:
return
@ -206,6 +327,10 @@ class CFDI(object):
return
def _receptor(self, datos):
receptor_name = datos['Nombre'].upper()
if receptor_name == PUBLIC and self._tipo_de_comprobante == CFDI_EGRESO:
receptor_name = datos['Nombre']
datos['Nombre'] = receptor_name
node_name = '{}:Receptor'.format(self._pre)
emisor = ET.SubElement(self._cfdi, node_name, datos)
return
@ -214,7 +339,8 @@ class CFDI(object):
from xml.sax.saxutils import escape, unescape
conceptos = ET.SubElement(self._cfdi, '{}:Conceptos'.format(self._pre))
for row in reversed(datos):
# ~ for row in reversed(datos):
for row in datos:
complemento = {}
if 'complemento' in row:
complemento = row.pop('complemento')
@ -274,6 +400,10 @@ class CFDI(object):
for field in fields:
if field in datos:
attributes[field] = datos[field]
if not attributes:
return
node_name = '{}:Impuestos'.format(self._pre)
impuestos = ET.SubElement(self._cfdi, node_name, attributes)
@ -390,6 +520,47 @@ class CFDI(object):
return
def _complemento_comercio_exterior(self, datos):
prefix = SAT['comercioe']['prefix']
emisor = datos.pop('emisor')
propietarios = datos.pop('propietarios', {})
receptor = datos.pop('receptor')
destinatario = datos.pop('destinatario', {})
mercancias = datos.pop('mercancias')
attr = {'Version': SAT['comercioe']['version']}
attr.update(datos)
ce = ET.SubElement(
self._complemento, f'{prefix}:ComercioExterior', attr)
attributes = {}
if 'Curp' in emisor:
attributes = {'Curp': emisor.pop('Curp')}
node = ET.SubElement(ce, '{}:Emisor'.format(prefix), attributes)
ET.SubElement(node, '{}:Domicilio'.format(prefix), emisor)
attributes = {}
if 'NumRegIdTrib' in receptor:
attributes = {'NumRegIdTrib': receptor.pop('NumRegIdTrib')}
node = ET.SubElement(ce, '{}:Receptor'.format(prefix), attributes)
ET.SubElement(node, '{}:Domicilio'.format(prefix), receptor)
node = ET.SubElement(ce, '{}:Mercancias'.format(prefix))
fields = ('Marca', 'Modelo', 'SubModelo', 'NumeroSerie')
for row in mercancias:
detalle = {}
for f in fields:
if f in row and row[f]:
detalle[f] = row[f]
row.pop(f)
concepto = ET.SubElement(node, '{}:Mercancia'.format(prefix), row)
if detalle:
ET.SubElement(
concepto, '{}:DescripcionesEspecificas'.format(prefix), detalle)
return
def _complementos(self, datos):
if not datos:
return
@ -398,62 +569,126 @@ class CFDI(object):
self._complemento = ET.SubElement(
self._cfdi, '{}:Complemento'.format(self._pre))
if self._carta_porte:
datos = datos['cartaporte']
ubicaciones = datos.pop('ubicaciones')
mercancias = datos.pop('mercancias', ())
tiposfigura = datos.pop('tiposfigura', ())
autotransporte = datos.pop('autotransporte', {})
identificacion = autotransporte.pop('identificacion')
seguros = autotransporte.pop('seguros')
remolques = autotransporte.pop('remolques')
atributos = {'Version': SAT['cartaporte']['version']}
atributos.update(datos)
prefix = SAT['cartaporte']['prefix']
node_carta = ET.SubElement(self._complemento, f'{prefix}:CartaPorte', atributos)
node = ET.SubElement(node_carta, f'{prefix}:Ubicaciones')
for ubicacion in ubicaciones:
domicilio = ubicacion.pop('domicilio', {})
dt = parser.parse(ubicacion['FechaHoraSalidaLlegada'])
ubicacion['FechaHoraSalidaLlegada'] = dt.isoformat()[:19]
sub_node = ET.SubElement(node, f'{prefix}:Ubicacion', ubicacion)
if domicilio:
ET.SubElement(sub_node, f'{prefix}:Domicilio', domicilio)
attr = mercancias
mercancias = attr.pop('mercancias')
node = ET.SubElement(node_carta, f'{prefix}:Mercancias', attr)
for mercancia in mercancias:
ET.SubElement(node, f'{prefix}:Mercancia', mercancia)
sub_node = ET.SubElement(node, f'{prefix}:Autotransporte', autotransporte)
ET.SubElement(sub_node, f'{prefix}:IdentificacionVehicular', identificacion)
ET.SubElement(sub_node, f'{prefix}:Seguros', seguros)
if remolques:
node_remolques = ET.SubElement(sub_node, f'{prefix}:Remolques')
for remolque in remolques:
ET.SubElement(node_remolques, f'{prefix}:Remolque', remolque)
if tiposfigura:
sub_node = ET.SubElement(node_carta, f'{prefix}:FiguraTransporte')
for figura in tiposfigura:
ET.SubElement(sub_node, f'{prefix}:TiposFigura', figura)
if self._divisas:
atributos = {
'version': SAT['divisas']['version'],
'tipoOperacion': self._divisas,
}
ET.SubElement(self._complemento, 'divisas:Divisas', atributos)
if 'ine' in datos:
atributos = {'Version': SAT['ine']['version']}
ine_key_entidad = datos['ine'].pop('ClaveEntidad', '')
ine_ambito = datos['ine'].pop('Ambito', '')
if ine_key_entidad:
ine_id_conta = datos['ine'].pop('IdContabilidad', '')
atributos.update(datos['ine'])
ET.SubElement(self._complemento, 'ine:INE', atributos)
node_ine = ET.SubElement(self._complemento, 'ine:INE', atributos)
if ine_key_entidad:
attr = {'ClaveEntidad': ine_key_entidad}
if ine_ambito:
attr['Ambito'] = ine_ambito
node_entidad = ET.SubElement(node_ine, 'ine:Entidad', attr)
attr = {'IdContabilidad': ine_id_conta}
ET.SubElement(node_entidad, 'ine:Contabilidad', attr)
if 'ce' in datos:
pre = 'cce11'
datos = datos.pop('ce')
emisor = datos.pop('emisor')
propietario = datos.pop('propietario')
receptor = datos.pop('receptor')
destinatario = datos.pop('destinatario')
conceptos = datos.pop('conceptos')
if 'pagos' in datos:
datos = datos.pop('pagos')
totales = datos.pop('totales')
relacionados = datos.pop('relacionados')
taxes_pay = datos.pop('taxes_pay')
pre = SAT['pagos']['prefix']
attributes = {}
attributes['xmlns:{}'.format(pre)] = \
'http://www.sat.gob.mx/ComercioExterior11'
attributes['xsi:schemaLocation'] = \
'http://www.sat.gob.mx/ComercioExterior11 ' \
'http://www.sat.gob.mx/sitio_internet/cfd/ComercioExterior11/ComercioExterior11.xsd'
attributes.update(datos)
ce = ET.SubElement(
complemento, '{}:ComercioExterior'.format(pre), attributes)
attributes = {'Version': SAT['pagos']['version']}
pagos = ET.SubElement(
self._complemento, '{}:Pagos'.format(pre), attributes)
attributes = {}
if 'Curp' in emisor:
attributes = {'Curp': emisor.pop('Curp')}
node = ET.SubElement(ce, '{}:Emisor'.format(pre), attributes)
ET.SubElement(node, '{}:Domicilio'.format(pre), emisor)
ET.SubElement(pagos, '{}:Totales'.format(pre), totales)
if propietario:
ET.SubElement(ce, '{}:Propietario'.format(pre), propietario)
node_pago = ET.SubElement(pagos, '{}:Pago'.format(pre), datos)
for row in relacionados:
taxes = row.pop('taxes')
node = ET.SubElement(node_pago, f'{pre}:DoctoRelacionado', row)
nodex_tax = None
if taxes['traslados'] or taxes['retenciones']:
node_tax = ET.SubElement(node, f'{pre}:ImpuestosDR')
if taxes['retenciones']:
node = ET.SubElement(node_tax, f'{pre}:RetencionesDR')
for tax in taxes['retenciones']:
ET.SubElement(node, f'{pre}:RetencionDR', tax)
if taxes['traslados']:
node = ET.SubElement(node_tax, f'{pre}:TrasladosDR')
for tax in taxes['traslados']:
ET.SubElement(node, f'{pre}:TrasladoDR', tax)
attributes = {}
if 'NumRegIdTrib' in receptor:
attributes = {'NumRegIdTrib': receptor.pop('NumRegIdTrib')}
node = ET.SubElement(ce, '{}:Receptor'.format(pre), attributes)
ET.SubElement(node, '{}:Domicilio'.format(pre), receptor)
if taxes_pay['traslados'] or taxes_pay['retenciones']:
node_tax = ET.SubElement(node_pago, f'{pre}:ImpuestosP')
if taxes_pay['retenciones']:
node = ET.SubElement(node_tax, f'{pre}:RetencionesP')
for key, importe in taxes_pay['retenciones'].items():
attr = {'ImpuestoP': key, 'ImporteP': importe}
ET.SubElement(node, f'{pre}:RetencionP', attr)
if taxes_pay['traslados']:
node = ET.SubElement(node_tax, f'{pre}:TrasladosP')
for key, tax in taxes_pay['traslados'].items():
ET.SubElement(node, f'{pre}:TrasladoP', tax)
attributes = {}
if 'NumRegIdTrib' in destinatario:
attributes = {'NumRegIdTrib': destinatario.pop('NumRegIdTrib')}
if 'Nombre' in destinatario:
attributes.update({'Nombre': destinatario.pop('Nombre')})
node = ET.SubElement(ce, '{}:Destinatario'.format(pre), attributes)
ET.SubElement(node, '{}:Domicilio'.format(pre), destinatario)
if 'leyendas' in datos:
pre = SAT['leyendas']['prefix']
attributes = {'version': SAT['leyendas']['version']}
node_leyend = ET.SubElement(
self._complemento, '{}:LeyendasFiscales'.format(pre), attributes)
for leyend in datos['leyendas']:
ET.SubElement(node_leyend, '{}:Leyenda'.format(pre), leyend)
if self._comercio_exterior:
datos = datos.pop('comercioe')
self._complemento_comercio_exterior(datos)
node = ET.SubElement(ce, '{}:Mercancias'.format(pre))
fields = ('Marca', 'Modelo', 'SubModelo', 'NumeroSerie')
for row in conceptos:
detalle = {}
for f in fields:
if f in row:
detalle[f] = row.pop(f)
concepto = ET.SubElement(node, '{}:Mercancia'.format(pre), row)
if detalle:
ET.SubElement(
concepto, '{}:DescripcionesEspecificas'.format(pre), detalle)
return

View File

@ -1,13 +0,0 @@
#!/usr/bin/env python
DEBUG = False
#~ Ecodex
ID_INTEGRADOR = ''
#~ Finkok
FINKOK= {
'USER': '',
'PASS': '',
}

View File

@ -1,90 +0,0 @@
#!/usr/bin/env python
from .conf import DEBUG, ID_INTEGRADOR, FINKOK
DEBUG = DEBUG
TIMEOUT = 10
#~ PACs que han proporcionado un entorno de pruebas libre y abierto
#~ ecodex, finkok
PAC = 'finkok'
def ecodex(debug):
NEW_SERVER = True
auth = {'ID': ID_INTEGRADOR}
if debug:
#~ No cambies este ID de pruebas
auth = {'ID': '2b3a8764-d586-4543-9b7e-82834443f219'}
base_url = 'https://servicios.ecodex.com.mx:4043/Servicio{}.svc?wsdl'
if NEW_SERVER:
base_url = 'https://serviciosnominas.ecodex.com.mx:4043/Servicio{}.svc?wsdl'
base_api = 'https://api.ecodex.com.mx/{}'
if debug:
base_url = 'https://wsdev.ecodex.com.mx:2045/Servicio{}.svc?wsdl'
base_api = 'https://pruebasapi.ecodex.com.mx/{}'
url = {
'seguridad': base_url.format('Seguridad'),
'clients': base_url.format('Clientes'),
'timbra': base_url.format('Timbrado'),
'token': base_api.format('token?version=2'),
'docs': base_api.format('api/documentos'),
'hash': base_api.format('api/Documentos/{}'),
'codes': {
'HASH': 'DUPLICIDAD EN HASH',
}
}
return auth, url
#~ IMPORTANTE: Si quieres hacer pruebas, con tu propio correo de usuario y
#~ contraseña, ponte en contacto con Finkok para que te asignen tus datos de
#~ acceso, consulta su documentación para ver las diferentes opciones de acceso.
#~ Si solo estas haciendo pruebas de timbrado y ancelación, con estos datos debería
#~ ser suficiente.
def finkok(debug):
USER = FINKOK['USER']
PASS = FINKOK['PASS']
TOKEN = ''
auth = {
'DEBUG': debug,
'USER': '',
'PASS': TOKEN or PASS,
'RESELLER': {'USER': USER, 'PASS': PASS}
}
if debug:
USER = 'pruebas-finkok@correolibre.net'
PASS = ''
TOKEN = '5c9a88da105bff9a8c430cb713f6d35269f51674bdc5963c1501b7316366'
auth = {
'DEBUG': debug,
'USER': USER,
'PASS': TOKEN or PASS,
'RESELLER': {
'USER': '',
'PASS': ''
}
}
base_url = 'https://facturacion.finkok.com/servicios/soap/{}.wsdl'
if debug:
base_url = 'http://demo-facturacion.finkok.com/servicios/soap/{}.wsdl'
url = {
'timbra': base_url.format('stamp'),
'quick_stamp': False,
'cancel': base_url.format('cancel'),
'client': base_url.format('registration'),
'util': base_url.format('utilities'),
'codes': {
'200': 'Comprobante timbrado satisfactoriamente',
'307': 'Comprobante timbrado previamente',
'205': 'No Encontrado',
}
}
return auth, url
AUTH, URL = globals()[PAC](DEBUG)

View File

@ -1,11 +1,14 @@
#!/usr/bin/env python3
import io
import os
import re
import smtplib
import ssl
import collections
from xml.sax.saxutils import escape
from collections import OrderedDict
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
@ -29,6 +32,9 @@ from reportlab.platypus import Paragraph, Table, TableStyle, Spacer
from reportlab.pdfgen import canvas
CANCEL = False
#~ https://github.com/kennethreitz/requests/blob/v1.2.3/requests/structures.py#L37
class CaseInsensitiveDict(collections.MutableMapping):
"""A case-insensitive ``dict``-like object.
@ -263,9 +269,7 @@ class SendMail(object):
def _login(self):
try:
if self._config['ssl'] and (
'gmail' in self._config['servidor'] or
'outlook' in self._config['servidor']):
if self._config['ssl'] and self._config['starttls']:
self._server = smtplib.SMTP(
self._config['servidor'],
self._config['puerto'], timeout=10)
@ -287,7 +291,7 @@ class SendMail(object):
if '535' in str(e):
self._error = 'Nombre de usuario o contraseña inválidos'
return False
print (e)
# ~ print (e)
if '534' in str(e) and 'gmail' in self._config['servidor']:
self._error = 'Necesitas activar el acceso a otras ' \
'aplicaciones en tu cuenta de GMail'
@ -340,6 +344,7 @@ class SendMail(object):
class NumberedCanvas(canvas.Canvas):
X = 20.59 * cm
XC = 21.6 * cm / 2 + 1.5 * cm
Y = 1.5 * cm
def __init__(self, *args, **kwargs):
@ -357,19 +362,33 @@ class NumberedCanvas(canvas.Canvas):
for state in self._saved_page_states:
self.__dict__.update(state)
self.draw_page_number(page_count)
self.draw_cancel()
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
return
def draw_page_number(self, page_count):
self.setFont('Helvetica', 8)
self.setFillColor(colors.darkred)
text = 'Página {} de {}'.format(self._pageNumber, page_count)
# ~ self.setFillColor(colors.darkred)
text = f'Página {self._pageNumber} de {page_count}'
self.drawRightString(self.X, self.Y, text)
text = 'Factura elaborada con software libre: www.empresalibre.net'
text = 'Este documento es una representación impresa de un CFDI'
self.drawCentredString(self.XC, self.Y, text)
text = 'Factura elaborada con software libre'
self.drawString(1.5 * cm, 1.5 * cm, text)
return
def draw_cancel(self):
global CANCEL
if CANCEL:
self.rotate(45)
self.setFont('Helvetica', 100)
self.setFillColor(colors.red)
text = 'Cancelada'
self.drawCentredString(20 * cm, 3 * cm, text)
return
class TemplateInvoice(BaseDocTemplate):
@ -418,6 +437,9 @@ class TemplateInvoice(BaseDocTemplate):
def _emisor(self, styles, data):
logo_path = data.pop('logo', '')
logo_style = styles.pop('logo', {})
logo_path2 = data.pop('logo2', '')
logo_style2 = styles.pop('logo2', {})
sucursales = styles.pop('sucursales', {})
for k, v in styles.items():
self._set_text(styles[k], data.get(k, ''))
@ -428,6 +450,28 @@ class TemplateInvoice(BaseDocTemplate):
for k in keys:
rect[k] = rect[k] * cm
self.canv.drawImage(logo_path, **rect)
if logo_path2 and logo_style2:
rect = logo_style2['rectangulo']
keys = ('x', 'y', 'width', 'height')
for k in keys:
rect[k] = rect[k] * cm
self.canv.drawImage(logo_path2, **rect)
if sucursales:
for k, sucursal in sucursales.items():
values = sucursal.pop('textos')
x = sucursal['rectangulo']['x']
y = sucursal['rectangulo']['y']
w = sucursal['rectangulo']['width']
h = sucursal['rectangulo']['height']
for v in values:
self._set_text(sucursal, v)
y -= h
sucursal['rectangulo']['x'] = x
sucursal['rectangulo']['y'] = y
sucursal['rectangulo']['width'] = w
sucursal['rectangulo']['height'] = h
return
def _receptor(self, styles, data):
@ -449,6 +493,7 @@ class TemplateInvoice(BaseDocTemplate):
def _comprobante1(self, styles, data):
title = styles.pop('titulo', {})
self.canv.setTitle(f"Factura {data.get('seriefolio', '')}")
for k, v in styles.items():
self._set_text(styles[k], data.get(k, ''))
@ -480,6 +525,12 @@ class TemplateInvoice(BaseDocTemplate):
fields = ('valorunitario', 'importe')
if field in fields:
return self._currency(value)
if field == 'descripcion':
html = '<font color="black" size=7>{}</font>'
style_bt = getSampleStyleSheet()['BodyText']
return Paragraph(html.format(value), style_bt)
return value
def _conceptos(self, conceptos):
@ -515,8 +566,8 @@ class TemplateInvoice(BaseDocTemplate):
('GRID', (0, 0), (-1, -1), 0.05 * cm, colors.white),
('ALIGN', (1, 0), (-1, -1), 'RIGHT'),
('FONTSIZE', (0, 0), (-1, -1), 8),
('BACKGROUND', (1, 0), (-1, -1), colors.linen),
('TEXTCOLOR', (1, 0), (-1, -1), colors.darkred),
('BACKGROUND', (1, 0), (-1, -1), colors.lightgrey),
('TEXTCOLOR', (1, 0), (-1, -1), colors.black),
('FACE', (1, 0), (-1, -1), 'Helvetica-Bold'),
]
table = Table(rows, colWidths=widths, spaceBefore=0.25*cm)
@ -524,7 +575,7 @@ class TemplateInvoice(BaseDocTemplate):
return table
def _comprobante2(self, styles, data):
leyenda = styles.pop('leyenda', {})
leyendas = styles.pop('leyendas', {})
ls = []
for k, v in styles.items():
@ -532,17 +583,27 @@ class TemplateInvoice(BaseDocTemplate):
if 'spaceBefore' in v['estilo']:
v['estilo']['spaceBefore'] = v['estilo']['spaceBefore'] * cm
ps = ParagraphStyle(**v['estilo'])
p = Paragraph(data[k], ps)
p = Paragraph(escape(data[k]), ps)
ls.append(p)
elif k=='formametodopago':
ps = ParagraphStyle(**v['estilo'])
v = f"{data['formadepago']} - {data['metododepago']}"
p = Paragraph(v, ps)
ls.append(p)
elif k=='monedatipocambio':
ps = ParagraphStyle(**v['estilo'])
v = f"{data['moneda']} - {data['tipocambio']}"
p = Paragraph(v, ps)
ls.append(p)
cbb = Image(data['path_cbb'])
cbb = Image(data['cbb'])
cbb.drawHeight = 4 * cm
cbb.drawWidth = 4 * cm
style_bt = getSampleStyleSheet()['BodyText']
style_bt.leading = 8
html_t = '<b><font size=6>{}</font></b>'
html = '<font color="darkred" size=5>{}</font>'
html = '<font color="black" size=5>{}</font>'
msg = 'Cadena original del complemento de certificación digital del SAT'
rows = [
(cbb, Paragraph(html_t.format('Sello Digital del CFDI'), style_bt)),
@ -558,13 +619,13 @@ class TemplateInvoice(BaseDocTemplate):
('FONTSIZE', (0, 0), (-1, -1), 6),
('SPAN', (0, 0), (0, -1)),
('FACE', (1, 0), (1, 0), 'Helvetica-Bold'),
('BACKGROUND', (1, 1), (1, 1), colors.linen),
('BACKGROUND', (1, 1), (1, 1), colors.lightgrey),
('TEXTCOLOR', (1, 1), (1, 1), colors.darkred),
('FACE', (1, 2), (1, 2), 'Helvetica-Bold'),
('BACKGROUND', (1, 3), (1, 3), colors.linen),
('BACKGROUND', (1, 3), (1, 3), colors.lightgrey),
('TEXTCOLOR', (1, 3), (1, 3), colors.darkred),
('FACE', (1, 4), (1, 4), 'Helvetica-Bold'),
('BACKGROUND', (1, 5), (1, 5), colors.linen),
('BACKGROUND', (1, 5), (1, 5), colors.lightgrey),
('TEXTCOLOR', (1, 5), (1, 5), colors.darkred),
('ALIGN', (0, 0), (0, 0), 'CENTER'),
('VALIGN', (0, 0), (0, 0), 'MIDDLE'),
@ -573,14 +634,14 @@ class TemplateInvoice(BaseDocTemplate):
table.setStyle(TableStyle(table_styles))
ls.append(table)
if leyenda:
if 'spaceBefore' in leyenda['estilo']:
leyenda['estilo']['spaceBefore'] = \
leyenda['estilo']['spaceBefore'] * cm
msg = 'Este documento es una representación impresa de un CFDI'
ps = ParagraphStyle(**leyenda['estilo'])
p = Paragraph(msg, ps)
ls.append(p)
if leyendas:
if 'spaceBefore' in leyendas['estilo']:
leyendas['estilo']['spaceBefore'] = \
leyendas['estilo']['spaceBefore'] * cm
for t in leyendas['textos']:
ps = ParagraphStyle(**leyendas['estilo'])
p = Paragraph(t, ps)
ls.append(p)
return ls
@ -596,8 +657,10 @@ class TemplateInvoice(BaseDocTemplate):
return self._data
@data.setter
def data(self, values):
#~ print (values)
global CANCEL
# ~ print (values)
self._data = values
CANCEL = self._data['cancelada']
rows = self._conceptos(self._data['conceptos'])
widths = [2 * cm, 9 * cm, 1.5 * cm, 2 * cm, 2 * cm, 3 * cm]
@ -607,13 +670,13 @@ class TemplateInvoice(BaseDocTemplate):
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('FACE', (0, 0), (-1, 0), 'Helvetica-Bold'),
('BACKGROUND', (0, 0), (-1, 0), colors.darkred),
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
('FONTSIZE', (0, 1), (-1, -1), 7),
('VALIGN', (0, 1), (-1, -1), 'TOP'),
('ALIGN', (0, 1), (0, -1), 'CENTER'),
('ALIGN', (2, 1), (2, -1), 'CENTER'),
('ALIGN', (3, 1), (5, -1), 'RIGHT'),
('LINEBELOW', (0, 1), (-1, -1), 0.05 * cm, colors.darkred),
('LINEBELOW', (0, 1), (-1, -1), 0.05 * cm, colors.grey),
('LINEBEFORE', (0, 1), (-1, -1), 0.05 * cm, colors.white),
]
table_conceptos = Table(rows, colWidths=widths, repeatRows=1)
@ -623,7 +686,7 @@ class TemplateInvoice(BaseDocTemplate):
comprobante = self._comprobante2(
self._custom_styles['comprobante'], self.data['comprobante'])
self._rows = [Spacer(0, 6*cm), table_conceptos, totales] + comprobante
self._rows = [Spacer(0, 5.7 * cm), table_conceptos, totales] + comprobante
def render(self):
frame = Frame(self.leftMargin, self.bottomMargin,
@ -1054,4 +1117,4 @@ class PrintTicket(object):
self._t(self.LEYENDA)
self._set('center', 'A', 'B')
self._t('empresalibre.net')
return
return

View File

@ -2,6 +2,7 @@
import falcon
from middleware import get_template
from urllib.parse import unquote
class AppEmpresas(object):
@ -47,6 +48,7 @@ class AppLogin(object):
session.invalidate()
values = req.params
values['rfc'] = values['rfc'].upper()
values['ip'] = req.remote_addr
result, user = self._db.authenticate(values)
if result['login']:
session.save()
@ -111,7 +113,14 @@ class AppValues(object):
values = req.params
session = req.env['beaker.session']
if req.path in ('values/titlelogin', '/values/empresas'):
if table == 'product':
original = values['name']
try:
values['name'] = unquote(req.query_string.split('=')[1])
except Exception as e:
values['name'] = original
if req.path in ('/values/titlelogin', '/values/empresas'):
req.context['result'] = self._db.get_values(table, values, session)
resp.status = falcon.HTTP_200
return
@ -279,7 +288,12 @@ class AppProducts(object):
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_products(values)
user = req.env['beaker.session']['userobj']
if 'opt' in values:
req.context['result'] = self._db.products_get(values, user)
else:
req.context['result'] = self._db.get_products(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
@ -302,7 +316,8 @@ class AppInvoices(object):
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_invoices(values)
session = req.env['beaker.session']
req.context['result'] = self._db.get_invoices(values, session['userobj'])
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
@ -311,9 +326,16 @@ class AppInvoices(object):
req.context['result'] = self._db.invoice(values, session['userobj'])
resp.status = falcon.HTTP_200
def on_put(self, req, resp):
values = req.params
session = req.env['beaker.session']
req.context['result'] = self._db.invoice_put(values, session['userobj'])
resp.status = falcon.HTTP_200
def on_delete(self, req, resp):
values = req.params
if self._db.delete('invoice', values['id']):
session = req.env['beaker.session']
if self._db.delete('invoice', values['id'], session['userobj']):
resp.status = falcon.HTTP_200
else:
resp.status = falcon.HTTP_204
@ -349,7 +371,8 @@ class AppTickets(object):
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_tickets(values)
session = req.env['beaker.session']
req.context['result'] = self._db.get_tickets(values, session['userobj'])
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
@ -420,7 +443,8 @@ class AppMovimientosBanco(object):
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.add_movbanco(values)
# ~ req.context['result'] = self._db.add_movbanco(values)
req.context['result'] = self._db.bankmovement(values)
resp.status = falcon.HTTP_200
def on_delete(self, req, resp):
@ -484,12 +508,24 @@ class AppNomina(object):
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_nomina(values)
user = req.env['beaker.session']['userobj']
if 'opt' in values:
req.context['result'] = self._db.nomina_get(values, user)
else:
by = values.get('by', '')
req.context['result'] = self._db.get_nomina(values)
if 'download' in by:
name = req.context['result']['name']
req.context['blob'] = req.context['result']['data']
resp.content_type = 'application/octet-stream'
resp.append_header(
'Content-Disposition', f'attachment; filename={name}')
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.nomina(values)
session = req.env['beaker.session']
req.context['result'] = self._db.nomina(values, session['userobj'])
resp.status = falcon.HTTP_200
def on_delete(self, req, resp):
@ -506,11 +542,286 @@ class AppDocumentos(object):
self._db = db
def on_get(self, req, resp, type_doc, id_doc):
# ~ print('TD', type_doc)
session = req.env['beaker.session']
req.context['result'], file_name, content_type = \
self._db.get_doc(type_doc, id_doc, session['rfc'])
if not type_doc in ('pdf', 'pre', 'tpdf'):
if not type_doc in ('pdf', 'pre', 'tpdf', 'pdfpago', 'html', 'nompdf'):
resp.append_header('Content-Disposition',
'attachment; filename={}'.format(file_name))
if type_doc in ('pdf', 'nompdf', 'pdfpago'):
resp.append_header('Content-Disposition',
'inline; filename={}'.format(file_name))
resp.content_type = content_type
resp.status = falcon.HTTP_200
# ~ Revisado
class AppInvoicePay(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_invoicepay(values)
resp.status = falcon.HTTP_200
class AppCfdiPay(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_cfdipay(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.cfdipay(values)
resp.status = falcon.HTTP_200
class AppSATBancos(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_sat_bancos(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.sat_bancos(values)
resp.status = falcon.HTTP_200
class AppSATFormaPago(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_sat_forma_pago(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.sat_forma_pago(values)
resp.status = falcon.HTTP_200
class AppSATLeyendaFiscales(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.sat_leyendas_fiscales_get(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.sat_leyendas_fiscales_post(values)
resp.status = falcon.HTTP_200
def on_delete(self, req, resp):
values = req.params
if self._db.sat_leyendas_fiscales_delete(values['id']):
resp.status = falcon.HTTP_200
else:
resp.status = falcon.HTTP_204
class AppSociosCuentasBanco(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_partners_accounts_bank(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.partners_accounts_bank(values)
resp.status = falcon.HTTP_200
class AppCert(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.cert_get(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.cert_post(values)
resp.status = falcon.HTTP_200
class AppSucursales(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.sucursales_get(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.sucursales_post(values)
resp.status = falcon.HTTP_200
class AppPartnerProducts(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.partner_products_get(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.partner_products_post(values)
resp.status = falcon.HTTP_200
class AppInventoryEntries(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.inventory_entries_get(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.inventory_entries_post(values, user)
resp.status = falcon.HTTP_200
class AppWareHouse(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.warehouse_get(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.warehouse_post(values, user)
resp.status = falcon.HTTP_200
class AppWareHouseProduct(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.warehouseproduct_get(values, user)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.warehouseproduct_post(values, user)
resp.status = falcon.HTTP_200
class AppTicketsDetails(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.ticketsdetails_get(values, user)
resp.status = falcon.HTTP_200
class AppUsers(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.users_get(values, user)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.users_post(values, user)
resp.status = falcon.HTTP_200
class AppSATUnidadesPeso(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.sat_unidades_peso_get(values, user)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.sat_unidades_peso_post(values, user)
resp.status = falcon.HTTP_200
class AppSATRegimenes(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.sat_regimenes_get(values, user)
resp.status = falcon.HTTP_200
class AppSociosRegimenes(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
user = req.env['beaker.session']['userobj']
req.context['result'] = self._db.socios_regimenes_get(values, user)
resp.status = falcon.HTTP_200

View File

@ -1,700 +0,0 @@
#!/usr/bin/env python
#~ import re
#~ from xml.etree import ElementTree as ET
#~ from requests import Request, Session, exceptions
import datetime
import hashlib
import os
import requests
import time
from lxml import etree
from xml.dom.minidom import parseString
from xml.sax.saxutils import escape, unescape
from uuid import UUID
from logbook import Logger
from zeep import Client
from zeep.plugins import HistoryPlugin
from zeep.cache import SqliteCache
from zeep.transports import Transport
from zeep.exceptions import Fault, TransportError
if __name__ == '__main__':
from configpac import DEBUG, TIMEOUT, AUTH, URL
else:
from .configpac import DEBUG, TIMEOUT, AUTH, URL
log = Logger('PAC')
#~ node = client.create_message(client.service, SERVICE, **args)
#~ print(etree.tostring(node, pretty_print=True).decode())
class Ecodex(object):
def __init__(self, auth, url):
self.auth = auth
self.url = url
self.codes = self.url['codes']
self.error = ''
self.message = ''
self._transport = Transport(cache=SqliteCache(), timeout=TIMEOUT)
self._plugins = None
self._history = None
if DEBUG:
self._history = HistoryPlugin()
self._plugins = [self._history]
def _get_token(self, rfc):
client = Client(self.url['seguridad'],
transport=self._transport, plugins=self._plugins)
try:
result = client.service.ObtenerToken(rfc, self._get_epoch())
except Fault as e:
self.error = str(e)
log.error(self.error)
return ''
s = '{}|{}'.format(self.auth['ID'], result.Token)
return hashlib.sha1(s.encode()).hexdigest()
def _get_token_rest(self, rfc):
data = {
'rfc': rfc,
'grant_type': 'authorization_token',
}
headers = {'Content-type': 'application/x-www-form-urlencoded'}
result = requests.post(URL['token'], data=data, headers=headers)
data = result.json()
s = '{}|{}'.format(AUTH['ID'], data['service_token'])
return hashlib.sha1(s.encode()).hexdigest(), data['access_token']
def _validate_xml(self, xml):
NS_CFDI = {'cfdi': 'http://www.sat.gob.mx/cfd/3'}
if os.path.isfile(xml):
tree = etree.parse(xml).getroot()
else:
tree = etree.fromstring(xml.encode())
fecha = tree.get('Fecha')
rfc = tree.xpath('string(//cfdi:Emisor/@Rfc)', namespaces=NS_CFDI)
data = {
'ComprobanteXML': etree.tostring(tree).decode(),
'RFC': rfc,
'Token': self._get_token(rfc),
'TransaccionID': self._get_epoch(fecha),
}
return data
def _get_by_hash(self, sh, rfc):
token, access_token = self._get_token_rest(rfc)
url = URL['hash'].format(sh)
headers = {
'Authorization': 'Bearer {}'.format(access_token),
'X-Auth-Token': token,
}
result = requests.get(url, headers=headers)
if result.status_code == 200:
print (result.json())
return
def timbra_xml(self, xml):
data = self._validate_xml(xml)
client = Client(self.url['timbra'],
transport=self._transport, plugins=self._plugins)
try:
result = client.service.TimbraXML(**data)
except Fault as e:
error = str(e)
if self.codes['HASH'] in error:
sh = error.split(' ')[3]
return self._get_by_hash(sh[:40], data['RFC'])
self.error = error
return ''
tree = parseString(result.ComprobanteXML.DatosXML)
xml = tree.toprettyxml(encoding='utf-8').decode('utf-8')
return xml
def _get_epoch(self, date=None):
if isinstance(date, str):
f = '%Y-%m-%dT%H:%M:%S'
e = int(time.mktime(time.strptime(date, f)))
else:
date = datetime.datetime.now()
e = int(time.mktime(date.timetuple()))
return e
def estatus_cuenta(self, rfc):
#~ Codigos:
#~ 100 = Cuenta encontrada
#~ 101 = RFC no dado de alta en el sistema ECODEX
token = self._get_token(rfc)
if not token:
return {}
data = {
'RFC': rfc,
'Token': token,
'TransaccionID': self._get_epoch()
}
client = Client(URL['clients'],
transport=self._transport, plugins=self._plugins)
try:
result = client.service.EstatusCuenta(**data)
except Fault as e:
log.error(str(e))
return
#~ print (result)
return result.Estatus
class Finkok(object):
def __init__(self, auth={}):
self.codes = URL['codes']
self.error = ''
self.message = ''
self._transport = Transport(cache=SqliteCache(), timeout=TIMEOUT)
self._plugins = None
self._history = None
self.uuid = ''
self.fecha = None
if DEBUG:
self._history = HistoryPlugin()
self._plugins = [self._history]
self._auth = AUTH
else:
self._auth = auth
def _debug(self):
if not DEBUG:
return
print('SEND', self._history.last_sent)
print('RESULT', self._history.last_received)
return
def _check_result(self, method, result):
# ~ print ('CODE', result.CodEstatus)
# ~ print ('INCIDENCIAS', result.Incidencias)
self.message = ''
MSG = {
'OK': 'Comprobante timbrado satisfactoriamente',
'307': 'Comprobante timbrado previamente',
}
status = result.CodEstatus
if status is None and result.Incidencias:
for i in result.Incidencias['Incidencia']:
self.error += 'Error: {}\n{}\n{}'.format(
i['CodigoError'], i['MensajeIncidencia'], i['ExtraInfo'])
return ''
if method == 'timbra' and status in (MSG['OK'], MSG['307']):
#~ print ('UUID', result.UUID)
#~ print ('FECHA', result.Fecha)
if status == MSG['307']:
self.message = MSG['307']
tree = parseString(result.xml)
response = tree.toprettyxml(encoding='utf-8').decode('utf-8')
self.uuid = result.UUID
self.fecha = result.Fecha
return response
def _load_file(self, path):
try:
with open(path, 'rb') as f:
data = f.read()
except Exception as e:
self.error = str(e)
return
return data
def _validate_xml(self, file_xml):
if os.path.isfile(file_xml):
try:
with open(file_xml, 'rb') as f:
xml = f.read()
except Exception as e:
self.error = str(e)
return False, ''
else:
xml = file_xml.encode('utf-8')
return True, xml
def _validate_uuid(self, uuid):
try:
UUID(uuid)
return True
except ValueError:
self.error = 'UUID no válido: {}'.format(uuid)
return False
def timbra_xml(self, file_xml):
self.error = ''
if not DEBUG and not self._auth:
self.error = 'Sin datos para timbrar'
return
method = 'timbra'
ok, xml = self._validate_xml(file_xml)
if not ok:
return ''
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': self._auth['USER'],
'password': self._auth['PASS'],
'xml': xml,
}
if URL['quick_stamp']:
try:
result = client.service.quick_stamp(**args)
except Fault as e:
self.error = str(e)
return
else:
try:
result = client.service.stamp(**args)
except Fault as e:
self.error = str(e)
return
except TransportError as e:
if '413' in str(e):
self.error = '413<BR><BR><b>Documento muy grande para timbrar</b>'
else:
self.error = str(e)
return
return self._check_result(method, result)
def _get_xml(self, uuid):
if not self._validate_uuid(uuid):
return ''
method = 'util'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': self._auth['USER'],
'password': self._auth['PASS'],
'uuid': uuid,
'taxpayer_id': self.rfc,
'invoice_type': 'I',
}
try:
result = client.service.get_xml(**args)
except Fault as e:
self.error = str(e)
return ''
except TransportError as e:
self.error = str(e)
return ''
if result.error:
self.error = result.error
return ''
tree = parseString(result.xml)
xml = tree.toprettyxml(encoding='utf-8').decode('utf-8')
return xml
def recupera_xml(self, file_xml='', uuid=''):
self.error = ''
if uuid:
return self._get_xml(uuid)
method = 'timbra'
ok, xml = self._validate_xml(file_xml)
if not ok:
return ''
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
try:
result = client.service.stamped(
xml, self._auth['user'], self._auth['pass'])
except Fault as e:
self.error = str(e)
return ''
return self._check_result(method, result)
def estatus_xml(self, uuid):
method = 'timbra'
if not self._validate_uuid(uuid):
return ''
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
try:
result = client.service.query_pending(
self._auth['USER'], self._auth['PASS'], uuid)
return result.status
except Fault as e:
self.error = str(e)
return ''
def cancel_xml(self, rfc, uuid, cer, key):
# ~ for u in uuids:
# ~ if not self._validate_uuid(u):
# ~ return ''
method = 'cancel'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
uuid_type = client.get_type('ns1:UUIDS')
sa = client.get_type('ns0:stringArray')
args = {
'UUIDS': uuid_type(uuids=sa(string=uuid)),
'username': self._auth['USER'],
'password': self._auth['PASS'],
'taxpayer_id': rfc,
'cer': cer,
'key': key,
'store_pending': True,
}
try:
result = client.service.cancel(**args)
except Fault as e:
self.error = str(e)
return ''
if result.CodEstatus and self.codes['205'] in result.CodEstatus:
self.error = result.CodEstatus
return ''
return result
def cancel_signature(self, file_xml):
method = 'cancel'
if os.path.isfile(file_xml):
root = etree.parse(file_xml).getroot()
else:
root = etree.fromstring(file_xml.encode())
xml = etree.tostring(root)
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': self._auth['USER'],
'password': self._auth['PASS'],
'xml': xml,
'store_pending': True,
}
try:
result = client.service.cancel_signature(**args)
return result
except Fault as e:
self.error = str(e)
return ''
def get_acuse(self, rfc, uuids, type_acuse='C'):
for u in uuids:
if not self._validate_uuid(u):
return ''
method = 'cancel'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': self._auth['USER'],
'password': self._auth['PASS'],
'taxpayer_id': rfc,
'uuid': '',
'type': type_acuse,
}
try:
result = []
for u in uuids:
args['uuid'] = u
r = client.service.get_receipt(**args)
result.append(r)
except Fault as e:
self.error = str(e)
return ''
return result
def estatus_cancel(self, uuids):
for u in uuids:
if not self._validate_uuid(u):
return ''
method = 'cancel'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': self._auth['USER'],
'password': self._auth['PASS'],
'uuid': '',
}
try:
result = []
for u in uuids:
args['uuid'] = u
r = client.service.query_pending_cancellation(**args)
result.append(r)
except Fault as e:
self.error = str(e)
return ''
return result
def add_token(self, rfc, email):
"""Agrega un nuevo token al cliente para timbrado.
Se requiere cuenta de reseller para usar este método
Args:
rfc (str): El RFC del cliente, ya debe existir
email (str): El correo del cliente, funciona como USER al timbrar
Returns:
dict
'username': 'username',
'status': True or False
'name': 'name',
'success': True or False
'token': 'Token de timbrado',
'message': None
"""
auth = AUTH['RESELLER']
method = 'util'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': auth['USER'],
'password': auth['PASS'],
'name': rfc,
'token_username': email,
'taxpayer_id': rfc,
'status': True,
}
try:
result = client.service.add_token(**args)
except Fault as e:
self.error = str(e)
return ''
return result
def get_date(self):
method = 'util'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
try:
result = client.service.datetime(AUTH['USER'], AUTH['PASS'])
except Fault as e:
self.error = str(e)
return ''
if result.error:
self.error = result.error
return
return result.datetime
def add_client(self, rfc, type_user=False):
"""Agrega un nuevo cliente para timbrado.
Se requiere cuenta de reseller para usar este método
Args:
rfc (str): El RFC del nuevo cliente
Kwargs:
type_user (bool): False == 'P' == Prepago or True == 'O' == On demand
Returns:
dict
'message':
'Account Created successfully'
'Account Already exists'
'success': True or False
"""
auth = AUTH['RESELLER']
tu = {False: 'P', True: 'O'}
method = 'client'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'reseller_username': auth['USER'],
'reseller_password': auth['PASS'],
'taxpayer_id': rfc,
'type_user': tu[type_user],
'added': datetime.datetime.now().isoformat()[:19],
}
try:
result = client.service.add(**args)
except Fault as e:
self.error = str(e)
return ''
return result
def edit_client(self, rfc, status=True):
"""
Se requiere cuenta de reseller para usar este método
status = 'A' or 'S'
"""
auth = AUTH['RESELLER']
sv = {False: 'S', True: 'A'}
method = 'client'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'reseller_username': auth['USER'],
'reseller_password': auth['PASS'],
'taxpayer_id': rfc,
'status': sv[status],
}
try:
result = client.service.edit(**args)
except Fault as e:
self.error = str(e)
return ''
return result
def get_client(self, rfc):
"""Regresa el estatus del cliente
.
Se requiere cuenta de reseller para usar este método
Args:
rfc (str): El RFC del emisor
Returns:
dict
'message': None,
'users': {
'ResellerUser': [
{
'status': 'A',
'counter': 0,
'taxpayer_id': '',
'credit': 0
}
]
} or None si no existe
"""
auth = AUTH['RESELLER']
method = 'client'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'reseller_username': auth['USER'],
'reseller_password': auth['PASS'],
'taxpayer_id': rfc,
}
try:
result = client.service.get(**args)
except Fault as e:
self.error = str(e)
return ''
except TransportError as e:
self.error = str(e)
return ''
return result
def assign_client(self, rfc, credit):
"""Agregar credito a un emisor
Se requiere cuenta de reseller para usar este método
Args:
rfc (str): El RFC del emisor, debe existir
credit (int): Cantidad de folios a agregar
Returns:
dict
'success': True or False,
'credit': nuevo credito despues de agregar or None
'message':
'Success, added {credit} of credit to {RFC}'
'RFC no encontrado'
"""
auth = AUTH['RESELLER']
method = 'client'
client = Client(
URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': auth['USER'],
'password': auth['PASS'],
'taxpayer_id': rfc,
'credit': credit,
}
try:
result = client.service.assign(**args)
except Fault as e:
self.error = str(e)
return ''
return result
def _get_data_sat(path):
BF = 'string(//*[local-name()="{}"]/@{})'
NS_CFDI = {'cfdi': 'http://www.sat.gob.mx/cfd/3'}
try:
if os.path.isfile(path):
tree = etree.parse(path).getroot()
else:
tree = etree.fromstring(path.encode())
data = {}
emisor = escape(
tree.xpath('string(//cfdi:Emisor/@rfc)', namespaces=NS_CFDI) or
tree.xpath('string(//cfdi:Emisor/@Rfc)', namespaces=NS_CFDI)
)
receptor = escape(
tree.xpath('string(//cfdi:Receptor/@rfc)', namespaces=NS_CFDI) or
tree.xpath('string(//cfdi:Receptor/@Rfc)', namespaces=NS_CFDI)
)
data['total'] = tree.get('total') or tree.get('Total')
data['emisor'] = emisor
data['receptor'] = receptor
data['uuid'] = tree.xpath(BF.format('TimbreFiscalDigital', 'UUID'))
except Exception as e:
print (e)
return {}
return '?re={emisor}&rr={receptor}&tt={total}&id={uuid}'.format(**data)
def get_status_sat(xml):
data = _get_data_sat(xml)
if not data:
return 'XML inválido'
URL = 'https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl'
client = Client(URL, transport=Transport(cache=SqliteCache()))
try:
result = client.service.Consulta(expresionImpresa=data)
except Exception as e:
return 'Error: {}'.format(str(e))
return result.Estado
def main():
return
if __name__ == '__main__':
main()

View File

@ -0,0 +1,4 @@
#!/usr/bin/env python
from .comerciodigital import PACComercioDigital
from .finkok import PACFinkok

View File

@ -0,0 +1,350 @@
#!/usr/bin/env python3
import argparse
import base64
import datetime
import getpass
import hashlib
import subprocess
from pathlib import Path
import lxml.etree as ET
import xmlsec
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.x509.oid import ExtensionOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from conf import TOKEN
class SATCertificate(object):
def __init__(self, cer=b'', key=b'', password=''):
self._error = ''
self._init_values()
self._get_data_cer(cer)
self._get_data_key(key, password)
# ~ if not password:
# ~ self._test()
# ~ def _test(self):
# ~ key = self._get_key('')
# ~ self._p = ''
# ~ self._key_der = key.private_bytes(
# ~ encoding=serialization.Encoding.DER,
# ~ format=serialization.PrivateFormat.PKCS8,
# ~ encryption_algorithm=serialization.BestAvailableEncryption(self._p.encode())
# ~ )
# ~ return
def _init_values(self):
self._rfc = ''
self._serial_number = ''
self._serial_number2 = ''
self._subject = ''
self._issuer = ''
self._not_before = None
self._not_after = None
self._is_fiel = False
self._are_couple = False
self._is_valid_time = False
self._key = b''
self._cer = b''
self._cer_pem = ''
self._cer_txt = ''
self._key_enc = b''
self._key_der = b''
self._p12 = b''
self._cer_modulus = 0
self._key_modulus = 0
return
def __str__(self):
msg = '\tRFC: {}\n'.format(self.rfc)
msg += '\tNo de Serie: {}\n'.format(self.serial_number)
msg += '\tVálido desde: {}\n'.format(self.not_before)
msg += '\tVálido hasta: {}\n'.format(self.not_after)
msg += '\tEs vigente: {}\n'.format(self.is_valid_time)
msg += '\tSon pareja: {}\n'.format(self.are_couple)
msg += '\tEs FIEL: {}\n'.format(self.is_fiel)
return msg
def __bool__(self):
return self.is_valid
def _get_hash(self):
digest = hashes.Hash(hashes.SHA512(), default_backend())
digest.update(self._rfc.encode())
digest.update(self._serial_number.encode())
digest.update(TOKEN.encode())
return digest.finalize()
def _get_data_cer(self, cer):
self._cer = cer
obj = x509.load_der_x509_certificate(cer, default_backend())
self._issuer = obj.issuer.rfc4514_string()
self._subject = obj.subject.rfc4514_string()
self._rfc = obj.subject.get_attributes_for_oid(
NameOID.X500_UNIQUE_IDENTIFIER)[0].value.split(' ')[0]
self._serial_number2 = '{0:x}'.format(obj.serial_number)
self._serial_number = self._serial_number2[1::2]
self._not_before = obj.not_valid_before
self._not_after = obj.not_valid_after
now = datetime.datetime.utcnow()
self._is_valid_time = (now > self.not_before) and (now < self.not_after)
if not self._is_valid_time:
msg = 'El certificado no es vigente'
self._error = msg
self._is_fiel = obj.extensions.get_extension_for_oid(
ExtensionOID.KEY_USAGE).value.key_agreement
self._cer_pem = obj.public_bytes(serialization.Encoding.PEM).decode()
self._cer_txt = ''.join(self._cer_pem.split('\n')[1:-2])
self._cer_modulus = obj.public_key().public_numbers().n
return
def _get_data_key(self, key, password):
self._key = key
self._keyp = password
self._key_enc = key
if not key or not password:
return
try:
obj = serialization.load_der_private_key(
key, password.encode(), default_backend())
except ValueError:
msg = 'La contraseña es incorrecta'
self._error = msg
return
p = self._get_hash()
self._key_enc = obj.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(p)
)
self._key_modulus = obj.public_key().public_numbers().n
self._are_couple = self._cer_modulus == self._key_modulus
if not self._are_couple:
msg = 'El CER y el KEY no son pareja'
self._error = msg
return
def _get_key(self, password):
if not password:
password = self._get_hash()
private_key = serialization.load_pem_private_key(
self._key_enc, password=password, backend=default_backend())
return private_key
def _get_key_pem(self):
obj = self._get_key('')
key_pem = obj.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
return key_pem
# Not work
def _get_p12(self):
obj = serialization.pkcs12.serialize_key_and_certificates('test',
self.key_pem, self.cer_pem, None,
encryption_algorithm=serialization.NoEncryption()
)
return obj
def sign(self, data, password=''):
private_key = self._get_key(password)
firma = private_key.sign(data, padding.PKCS1v15(), hashes.SHA256())
return base64.b64encode(firma).decode()
def sign_xml(self, tree):
node = xmlsec.tree.find_node(tree, xmlsec.constants.NodeSignature)
ctx = xmlsec.SignatureContext()
key = xmlsec.Key.from_memory(
self.key_pem, xmlsec.constants.KeyDataFormatPem)
ctx.key = key
ctx.sign(node)
node = xmlsec.tree.find_node(tree, 'X509Certificate')
node.text = self.cer_txt
node = xmlsec.tree.find_node(tree, 'X509IssuerName')
node.text = self.issuer
node = xmlsec.tree.find_node(tree, 'X509SerialNumber')
node.text = self.serial_number
node = xmlsec.tree.find_node(tree, 'SignatureValue')
node.text = node.text.replace('\n', '')
node = xmlsec.tree.find_node(tree, 'Modulus')
node.text = node.text.replace('\n', '')
# ~ xml_signed = ET.tostring(tree,
# ~ xml_declaration=True, encoding='UTF-8').decode()
xml_signed = ET.tostring(tree, encoding='UTF-8').decode().replace('\n', '')
return xml_signed
@property
def rfc(self):
return self._rfc
@property
def serial_number(self):
return self._serial_number
@property
def serial_number2(self):
return self._serial_number2
@property
def issuer(self):
return self._issuer
@property
def subject(self):
return self._subject
@property
def not_before(self):
return self._not_before
@property
def not_after(self):
return self._not_after
@property
def is_fiel(self):
return self._is_fiel
@property
def are_couple(self):
return self._are_couple
@property
def is_valid(self):
return not bool(self.error)
@property
def is_valid_time(self):
return self._is_valid_time
@property
def cer(self):
return self._cer
@property
def cer_pem(self):
return self._cer_pem.encode()
@property
def cer_txt(self):
return self._cer_txt
@property
def key_pem(self):
return self._get_key_pem()
@property
def key_enc(self):
return self._key_enc
@property
def p12(self):
return self._get_p12()
@property
def error(self):
return self._error
@classmethod
def save_cert(cls, obj):
import hashlib
cer = x509.load_pem_x509_certificate(obj.cer_pem.encode(), default_backend())
cer_der = cer.public_bytes(serialization.Encoding.DER)
token = hashlib.md5(obj.rfc.encode()).hexdigest()
path = Path(f'/tmp/{obj.rfc}.key')
path.write_text(obj.key_enc)
args = f'openssl rsa -inform PEM -outform PEM -in "{str(path)}" -passin pass:{token}'
pem = subprocess.check_output(args, shell=True).decode()
key = serialization.load_pem_private_key(
pem.encode(), password=None, backend=default_backend())
digest = hashes.Hash(hashes.SHA512(), default_backend())
digest.update(obj.rfc.encode())
digest.update(obj.serie.encode())
digest.update(TOKEN.encode())
p = digest.finalize()
key_enc = key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(p)
)
cert = SATCertificate(cer_der, key_enc)
obj.key_enc = cert.key_enc
obj.cer = cert.cer
obj.serie = cert.serial_number
obj.desde = cert.not_before
obj.hasta = cert.not_after
obj.save()
return
def main(args):
# ~ contra = getpass.getpass('Introduce la contraseña del archivo KEY: ')
contra = '12345678a'
if not contra.strip():
msg = 'La contraseña es requerida'
print(msg)
return
path_cer = Path(args.cer)
path_key = Path(args.key)
if not path_cer.is_file():
msg = 'El archivo CER es necesario'
print(msg)
return
if not path_key.is_file():
msg = 'El archivo KEY es necesario'
print(msg)
return
cer = path_cer.read_bytes()
key = path_key.read_bytes()
cert = SATCertificate(cer, key, contra)
if cert.error:
print(cert.error)
else:
print(cert)
return
def _process_command_line_arguments():
parser = argparse.ArgumentParser(description='CFDI Certificados')
help = 'Archivo CER'
parser.add_argument('-c', '--cer', help=help, default='')
help = 'Archivo KEY'
parser.add_argument('-k', '--key', help=help, default='')
args = parser.parse_args()
return args
if __name__ == '__main__':
args = _process_command_line_arguments()
main(args)

View File

@ -0,0 +1,3 @@
#!/usr/bin/env python3
from .comercio import PACComercioDigital

View File

@ -0,0 +1,431 @@
#!/usr/bin/env python
# ~
# ~ PAC
# ~ Copyright (C) 2018-2019 Mauricio Baeza Servin - public [AT] elmau [DOT] net
# ~
# ~ This program is free software: you can redistribute it and/or modify
# ~ it under the terms of the GNU General Public License as published by
# ~ the Free Software Foundation, either version 3 of the License, or
# ~ (at your option) any later version.
# ~
# ~ This program is distributed in the hope that it will be useful,
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# ~ GNU General Public License for more details.
# ~
# ~ You should have received a copy of the GNU General Public License
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
import logging
import lxml.etree as ET
import requests
from requests.exceptions import ConnectionError
from .conf import DEBUG
# ~ , AUTH
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
LOG_DATE = '%d/%m/%Y %H:%M:%S'
logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m')
logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m')
logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m')
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE)
log = logging.getLogger(__name__)
logging.getLogger('requests').setLevel(logging.ERROR)
TIMEOUT = 10
NAMESPACES = {
'3.3': 'http://www.sat.gob.mx/cfd/3',
'4.0': 'http://www.sat.gob.mx/cfd/4',
'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital',
}
def pretty_print_POST(req):
"""
At this point it is completely built and ready
to be fired; it is "prepared".
However pay attention at the formatting used in
this function because it is programmed to be pretty
printed and may differ from the actual request.
"""
print('{}\n{}\r\n{}\r\n\r\n{}'.format(
'-----------START-----------',
req.method + ' ' + req.url,
'\r\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
req.body,
))
class PACComercioDigital(object):
ws = 'https://{}.comercio-digital.mx/{}'
api = 'https://app2.comercio-digital.mx/{}'
URL = {
'timbra': ws.format('ws', 'timbre4/timbrarV5'),
'cancel': ws.format('cancela', 'cancela4/cancelarUuid'),
'cancelxml': ws.format('cancela', 'cancela4/cancelarXml'),
'status': ws.format('cancela', 'arws/consultaEstatus'),
'client': api.format('x3/altaEmpresa'),
'saldo': api.format('x3/saldo'),
'timbres': api.format('x3/altaTimbres'),
}
CODES = {
'000': '000 Exitoso',
'004': '004 RFC {} ya esta dado de alta con Estatus=A',
'704': '704 Usuario Invalido',
'702': '702 Error rfc/empresa invalido',
}
NS_CFDI = {
'cfdi': 'http://www.sat.gob.mx/cfd/4',
'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital',
}
if DEBUG:
ws = 'https://pruebas.comercio-digital.mx/{}'
ws6 = 'https://pruebas6.comercio-digital.mx/arws/{}'
URL = {
'timbra': ws.format('timbre4/timbrarV5'),
'cancel': ws.format('cancela4/cancelarUuid'),
'cancelxml': ws.format('cancela4/cancelarXml'),
'status': ws6.format('consultaEstatus'),
'client': api.format('x3/altaEmpresa'),
'saldo': api.format('x3/saldo'),
'timbres': api.format('x3/altaTimbres'),
}
def __init__(self):
self.error = ''
def _error(self, msg):
self.error = str(msg)
log.error(msg)
return
def _post(self, url, data, headers={}):
result = None
headers['host'] = url.split('/')[2]
headers['Content-type'] = 'text/plain'
headers['Connection'] = 'Keep-Alive'
headers['Expect'] = '100-continue'
if DEBUG:
req = requests.Request('POST', url, headers=headers, data=data)
prepared = req.prepare()
pretty_print_POST(prepared)
try:
result = requests.post(url, data=data, headers=headers, timeout=TIMEOUT)
except ConnectionError as e:
self._error(e)
return result
def _validate_cfdi(self, xml):
"""
Comercio Digital solo soporta la declaración con doble comilla
"""
# ~ tree = ET.fromstring(xml.encode())
# ~ xml = ET.tostring(tree,
# ~ pretty_print=True, doctype='<?xml version="1.0" encoding="utf-8"?>')
return xml.encode('utf-8')
def stamp(self, cfdi, auth):
# ~ if DEBUG or not auth:
# ~ auth = AUTH
url = self.URL['timbra']
headers = {
'usrws': auth['user'],
'pwdws': auth['pass'],
'tipo': 'XML',
}
cfdi = self._validate_cfdi(cfdi)
result = self._post(url, cfdi, headers)
if result is None:
return ''
if result.status_code != 200:
return ''
if 'errmsg' in result.headers:
self._error(result.headers['errmsg'])
return ''
xml = result.content
tree = ET.fromstring(xml)
cfdi_uuid = tree.xpath(
'string(//cfdi:Complemento/tdf:TimbreFiscalDigital/@UUID)',
namespaces=self.NS_CFDI)
date_stamped = tree.xpath(
'string(//cfdi:Complemento/tdf:TimbreFiscalDigital/@FechaTimbrado)',
namespaces=self.NS_CFDI)
data = {
'xml': xml.decode(),
'uuid': cfdi_uuid,
'date': date_stamped,
}
return data
def _get_data_cancel(self, cfdi, info, auth):
info['tipo'] = 'cfdi'
info['key'] = base64.b64encode(info['key_enc']).decode()
info['cer'] = base64.b64encode(info['cer_ori']).decode()
tree = ET.fromstring(cfdi.encode())
version = tree.attrib['Version']
namespaces = {
'cfdi': NAMESPACES[version],
'tdf': NAMESPACES['tdf'],
}
tipo = tree.xpath(
'string(//cfdi:Comprobante/@TipoDeComprobante)',
namespaces=namespaces)
total = tree.xpath(
'string(//cfdi:Comprobante/@Total)',
namespaces=namespaces)
rfc_emisor = tree.xpath(
'string(//cfdi:Comprobante/cfdi:Emisor/@Rfc)',
namespaces=namespaces)
rfc_receptor = tree.xpath(
'string(//cfdi:Comprobante/cfdi:Receptor/@Rfc)',
namespaces=namespaces)
uid = tree.xpath(
'string(//cfdi:Complemento/tdf:TimbreFiscalDigital/@UUID)',
namespaces=namespaces)
data = (
f"USER={auth['user']}",
f"PWDW={auth['pass']}",
f"RFCE={rfc_emisor}",
f"UUID={uid}",
f"PWDK={info['pass']}",
f"KEYF={info['key']}",
f"CERT={info['cer']}",
f"TIPO1={info['tipo']}",
f"ACUS=SI",
f"RFCR={rfc_receptor}",
f"TIPOC={tipo}",
f"TOTAL={total}",
f"UUIDREL={info['args']['uuid']}",
f"MOTIVO={info['args']['reason']}",
)
return '\n'.join(data)
def cancel(self, cfdi, info, auth):
# ~ if DEBUG or not auth:
# ~ auth = AUTH
url = self.URL['cancel']
data = self._get_data_cancel(cfdi, info, auth)
result = self._post(url, data)
if result is None:
return ''
if result.status_code != 200:
return ''
if result.headers['codigo'] != '000':
self._error(result.headers['errmsg'])
return ''
tree = ET.fromstring(result.text)
date_cancel = tree.xpath('string(//Acuse/@Fecha)')[:19]
data = {
'acuse': result.text,
'date': date_cancel,
}
return data
def _get_headers_cancel_xml(self, cfdi, info, auth):
NS_CFDI = {
'cfdi': 'http://www.sat.gob.mx/cfd/3',
'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital',
}
tree = ET.fromstring(cfdi.encode())
tipocfdi = tree.xpath(
'string(//cfdi:Comprobante/@TipoDeComprobante)',
namespaces=NS_CFDI)
total = tree.xpath(
'string(//cfdi:Comprobante/@Total)',
namespaces=NS_CFDI)
rfc_receptor = tree.xpath(
'string(//cfdi:Comprobante/cfdi:Receptor/@Rfc)',
namespaces=NS_CFDI)
headers = {
'usrws': auth['user'],
'pwdws': auth['pass'],
'rfcr': rfc_receptor,
'total': total,
'tipocfdi': tipocfdi,
}
headers.update(info)
return headers
def cancel_xml(self, xml, auth, cfdi='', info={'tipo': 'cfdi'}):
# ~ if DEBUG or not auth:
# ~ auth = AUTH
url = self.URL['cancelxml']
headers = self._get_headers_cancel_xml(cfdi, info, auth)
result = self._post(url, xml, headers)
if result is None:
return ''
if result.status_code != 200:
return ''
if result.headers['codigo'] != '000':
self._error(result.headers['errmsg'])
return ''
tree = ET.fromstring(result.text)
date_cancel = tree.xpath('string(//Acuse/@Fecha)')[:19]
data = {
'acuse': result.text,
'date': date_cancel,
}
return data
def status(self, data, auth):
# ~ if not auth:
# ~ auth = AUTH
url = self.URL['status']
data = (
f"USER={auth['user']}",
f"PWDW={auth['pass']}",
f"RFCR={data['rfc_receptor']}",
f"RFCE={data['rfc_emisor']}",
f"TOTAL={data['total']}",
f"UUID={data['uuid']}",
)
data = '\n'.join(data)
result = self._post(url, data)
if result is None:
return ''
if result.status_code != 200:
self._error(result.status_code)
return self.error
return result.text
def _get_data_client(self, auth, values):
data = [f"usr_ws={auth['user']}", f"pwd_ws={auth['pass']}"]
fields = (
'rfc_contribuyente',
'nombre_contribuyente',
'calle',
'noExterior',
'noInterior',
'colonia',
'localidad',
'municipio',
'estado',
'pais',
'cp',
'contacto',
'telefono',
'email',
'rep_nom',
'rep_rfc',
'email_fact',
'pwd_asignado',
)
data += [f"{k}={values[k]}" for k in fields]
return '\n'.join(data)
def client_add(self, data, auth):
# ~ auth = AUTH
url = self.URL['client']
data = self._get_data_client(auth, data)
result = self._post(url, data)
if result is None:
return False
if result.status_code != 200:
self._error(f'Code: {result.status_code}')
return False
if result.text != self.CODES['000']:
self._error(result.text)
return False
return True
def client_balance(self, data, rfc=''):
url = self.URL['saldo']
host = url.split('/')[2]
headers = {
'Content-type': 'text/plain',
'Host': host,
'Connection' : 'Keep-Alive',
}
data = {'usr': data['user'], 'pwd': data['pass']}
try:
result = requests.get(url, params=data, headers=headers, timeout=TIMEOUT)
except ConnectionError as e:
self._error(e)
return ''
if result.status_code != 200:
return ''
if result.text == self.CODES['704']:
self._error(result.text)
return ''
if result.text == self.CODES['702']:
self._error(result.text)
return ''
return result.text
def client_add_timbres(self, data, auth):
# ~ if not auth:
# ~ auth = AUTH
url = self.URL['timbres']
data = '\n'.join((
f"usr_ws={auth['user']}",
f"pwd_ws={auth['pass']}",
f"rfc_recibir={data['rfc']}",
f"num_timbres={data['timbres']}"
))
result = self._post(url, data)
if result is None:
return False
if result.status_code != 200:
self._error(f'Code: {result.status_code}')
return False
if result.text != self.CODES['000']:
self._error(result.text)
return False
return True

View File

@ -0,0 +1,38 @@
#!/usr/bin/env python
# ~
# ~ PAC
# ~ Copyright (C) 2018-2019 Mauricio Baeza Servin - public [AT] elmau [DOT] net
# ~
# ~ This program is free software: you can redistribute it and/or modify
# ~ it under the terms of the GNU General Public License as published by
# ~ the Free Software Foundation, either version 3 of the License, or
# ~ (at your option) any later version.
# ~
# ~ This program is distributed in the hope that it will be useful,
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# ~ GNU General Public License for more details.
# ~
# ~ You should have received a copy of the GNU General Public License
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
# ~ Siempre consulta la documentación de PAC
# ~ AUTH = Las credenciales de timbrado proporcionadas por el PAC
# ~ NO cambies las credenciales de prueba
DEBUG = False
AUTH = {
'user': '',
'pass': '',
}
if DEBUG:
AUTH = {
'user': 'AAA010101AAA',
'pass': 'PWD',
}

View File

@ -0,0 +1,3 @@
#!/usr/bin/env python3
from .finkok import PACFinkok

View File

@ -0,0 +1,46 @@
#!/usr/bin/env python
# ~
# ~ PAC
# ~ Copyright (C) 2018-2019 Mauricio Baeza Servin - public [AT] elmau [DOT] net
# ~
# ~ This program is free software: you can redistribute it and/or modify
# ~ it under the terms of the GNU General Public License as published by
# ~ the Free Software Foundation, either version 3 of the License, or
# ~ (at your option) any later version.
# ~
# ~ This program is distributed in the hope that it will be useful,
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# ~ GNU General Public License for more details.
# ~
# ~ You should have received a copy of the GNU General Public License
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
# ~ Siempre consulta la documentación de PAC
# ~ AUTH = Las credenciales de timbrado proporcionadas por el PAC
# ~ NO cambies las credenciales de prueba
DEBUG = False
AUTH = {
'user': '',
'pass': '',
'RESELLER': {
'user': '',
'pass': ''
}
}
if DEBUG:
AUTH = {
'user': 'pruebas-finkok@correolibre.net',
'pass': '5c9a88da105bff9a8c430cb713f6d35269f51674bdc5963c1501b7316366',
'RESELLER': {
'user': '',
'pass': ''
}
}

View File

@ -0,0 +1,580 @@
#!/usr/bin/env python
# ~
# ~ PAC
# ~ Copyright (C) 2018-2019 Mauricio Baeza Servin - public [AT] elmau [DOT] net
# ~
# ~ This program is free software: you can redistribute it and/or modify
# ~ it under the terms of the GNU General Public License as published by
# ~ the Free Software Foundation, either version 3 of the License, or
# ~ (at your option) any later version.
# ~
# ~ This program is distributed in the hope that it will be useful,
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# ~ GNU General Public License for more details.
# ~
# ~ You should have received a copy of the GNU General Public License
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
# ~ import base64
import datetime
import logging
import os
import re
from io import BytesIO
from xml.sax.saxutils import unescape
import lxml.etree as ET
from zeep import Client
from zeep.plugins import Plugin
from zeep.cache import SqliteCache
from zeep.transports import Transport
from zeep.exceptions import Fault, TransportError
from requests.exceptions import ConnectionError
from .conf import DEBUG, AUTH
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
LOG_DATE = '%d/%m/%Y %H:%M:%S'
logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m')
logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m')
logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m')
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE)
log = logging.getLogger(__name__)
logging.getLogger('requests').setLevel(logging.ERROR)
logging.getLogger('zeep').setLevel(logging.ERROR)
TIMEOUT = 10
DEBUG_SOAP = False
class DebugPlugin(Plugin):
def _to_string(self, envelope, name):
if DEBUG_SOAP:
data = ET.tostring(envelope, pretty_print=True, encoding='utf-8').decode()
path = f'/tmp/soap_{name}.xml'
with open(path, 'w') as f:
f.write(data)
# ~ print(data)
return
def egress(self, envelope, http_headers, operation, binding_options):
self._to_string(envelope, 'request')
return envelope, http_headers
def ingress(self, envelope, http_headers, operation):
self._to_string(envelope, 'response')
return envelope, http_headers
class PACFinkok(object):
WS = 'https://facturacion.finkok.com/servicios/soap/{}.wsdl'
NS_TYPE = 'ns1'
if DEBUG:
WS = 'https://demo-facturacion.finkok.com/servicios/soap/{}.wsdl'
NS_TYPE = 'ns0'
URL = {
'quick_stamp': False,
'timbra': WS.format('stamp'),
'cancel': WS.format('cancel'),
'client': WS.format('registration'),
'util': WS.format('utilities'),
}
CODE = {
'200': 'Comprobante timbrado satisfactoriamente',
'205': 'No Encontrado',
'307': 'Comprobante timbrado previamente',
'702': 'No se encontro el RFC del emisor',
'IP': 'Invalid Passphrase',
'IPMSG': 'Frase de paso inválida',
'NE': 'No Encontrado',
}
def __init__(self):
self._error = ''
self._transport = Transport(cache=SqliteCache(), timeout=TIMEOUT)
self._plugins = [DebugPlugin()]
@property
def error(self):
return self._error
def _validate_result(self, result):
if hasattr(result, 'Incidencias') and not result.Incidencias is None:
fault = result.Incidencias.Incidencia[0]
cod_error = fault.CodigoError.encode('utf-8').decode()
msg_error = fault.MensajeIncidencia.encode('utf-8').decode()
error = 'Error: {}\n{}'.format(cod_error, msg_error)
if cod_error == '307':
return result
self._error = self.CODE.get(cod_error, error)
return {}
if hasattr(result, 'CodEstatus'):
ce = result.CodEstatus
if ce is None:
return result
if ce == self.CODE['IP']:
self._error = self.CODE['IPMSG']
return {}
if self.CODE['NE'] in ce:
self._error = 'UUID ' + self.CODE['NE']
return {}
if ce == 'UUID Not Found':
self._error = 'UUID ' + self.CODE['NE']
return {}
if self.CODE['200'] != ce:
self._error = ce
return {}
return result
return result
def _get_result(self, client, method, args):
self._error = ''
try:
result = getattr(client.service, method)(**args)
except Fault as e:
self._error = str(e)
return {}
except TransportError as e:
if '413' in str(e):
self._error = '413<BR><BR><b>Documento muy grande para timbrar</b>'
else:
self._error = str(e)
return {}
except ConnectionError as e:
msg = '502 - Error de conexión'
self._error = msg
return {}
return self._validate_result(result)
def _to_string(self, data):
root = ET.parse(BytesIO(data.encode('utf-8'))).getroot()
xml = ET.tostring(root,
pretty_print=True, xml_declaration=True, encoding='utf-8')
return xml.decode('utf-8')
def stamp(self, cfdi, auth={}):
if DEBUG or not auth:
auth = AUTH
method = 'timbra'
client = Client(self.URL[method],
transport=self._transport, plugins=self._plugins)
args = {
'username': auth['user'],
'password': auth['pass'],
'xml': cfdi.encode('utf-8'),
}
result = self._get_result(client, 'stamp', args)
if self.error:
log.error(self.error)
return ''
data = {
'xml': self._to_string(result.xml),
'uuid': result.UUID,
'date': result.Fecha,
}
return data
def _get_data_cancel(self, cfdi):
VERSIONS = {
'3.3': 'http://www.sat.gob.mx/cfd/3',
'4.0': 'http://www.sat.gob.mx/cfd/4',
}
NS_CFDI = {
'tdf': 'http://www.sat.gob.mx/TimbreFiscalDigital',
}
tree = ET.fromstring(cfdi.encode())
version = tree.attrib['Version']
NS_CFDI['cfdi'] = VERSIONS[version]
rfc_emisor = tree.xpath(
'string(//cfdi:Comprobante/cfdi:Emisor/@Rfc)',
namespaces=NS_CFDI)
cfdi_uuid = tree.xpath(
'string(//cfdi:Complemento/tdf:TimbreFiscalDigital/@UUID)',
namespaces=NS_CFDI)
return rfc_emisor, cfdi_uuid
def cancel(self, cfdi, info, auth={}):
if DEBUG or not auth:
auth = AUTH
rfc_emisor, cfdi_uuid = self._get_data_cancel(cfdi)
method = 'cancel'
client = Client(self.URL[method],
transport=self._transport, plugins=self._plugins)
uuid_type = client.get_type(f'{self.NS_TYPE}:UUIDS')
ns1_uuid = client.get_type(f'{self.NS_TYPE}:UUID')
# ~ sa = client.get_type('ns0:stringArray')
data_uuid = {
'UUID': cfdi_uuid,
'FolioSustitucion': info['args']['uuid'],
'Motivo': info['args']['reason'],
}
# ~ 'UUIDS': uuid_type(uuids=sa(string=cfdi_uuid)),
args = {
'UUIDS': uuid_type(ns1_uuid(**data_uuid)),
'username': auth['user'],
'password': auth['pass'],
'taxpayer_id': rfc_emisor,
'cer': info['cer'],
'key': info['key'],
'store_pending': False,
}
result = self._get_result(client, 'cancel', args)
if self.error:
log.error(self.error)
return ''
folio = result['Folios']['Folio'][0]
status = folio['EstatusUUID']
if status != '201':
log.debug(f'Cancel status: {status} - {cfdi_uuid}')
data = {
'acuse': result['Acuse'],
'date': result['Fecha'],
}
return data
def cancel_xml(self, xml, auth={}, cfdi=''):
if DEBUG or not auth:
auth = AUTH
method = 'cancel'
client = Client(self.URL[method],
transport=self._transport, plugins=self._plugins)
client.set_ns_prefix('can', 'http://facturacion.finkok.com/cancel')
args = {
'xml': xml.encode(),
'username': auth['user'],
'password': auth['pass'],
'store_pending': False,
}
result = self._get_result(client, 'cancel_signature', args)
if self.error:
log.error(self.error)
return ''
folio = result['Folios']['Folio'][0]
status = folio['EstatusUUID']
if status == '708':
self._error = 'Error 708 del SAT, intenta más tarde.'
log.error(self.error)
return ''
if status != '201':
log.debug(f'Cancel status: {status} -')
data = {
'acuse': result['Acuse'],
'date': result['Fecha'],
}
return data
def client_add(self, rfc, type_user=False):
"""Agrega un nuevo cliente para timbrado.
Se requiere cuenta de reseller para usar este método
Args:
rfc (str): El RFC del nuevo cliente
Kwargs:
type_user (bool):
False == 'P' == Prepago
True == 'O' == On demand
Returns:
True or False
origin PAC
'message':
'Account Created successfully'
'Account Already exists'
'success': True or False
"""
auth = AUTH['RESELLER']
tu = {True: 'O', False: 'P'}
method = 'client'
client = Client(
self.URL[method], transport=self._transport, plugins=self._plugins)
args = {
'reseller_username': auth['user'],
'reseller_password': auth['pass'],
'taxpayer_id': rfc,
'type_user': tu[type_user],
'added': datetime.datetime.now().isoformat()[:19],
}
result = self._get_result(client, 'add', args)
if self.error:
return False
if not result.success:
self.error = result.message
return False
# ~ PAC success debería ser False
msg = 'Account Already exists'
if result.message == msg:
self.error = msg
return True
return result.success
def client_get_token(self, rfc, email):
"""Genera un nuevo token al cliente para timbrado.
Se requiere cuenta de reseller para usar este método
Args:
rfc (str): El RFC del cliente, ya debe existir
email (str): El correo del cliente, funciona como USER al timbrar
Returns:
token (str): Es la contraseña para timbrar
origin PAC
dict
'username': 'username',
'status': True or False
'name': 'name',
'success': True or False
'token': 'Token de timbrado',
'message': None
"""
auth = AUTH['RESELLER']
method = 'util'
client = Client(
self.URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': auth['user'],
'password': auth['pass'],
'name': rfc,
'token_username': email,
'taxpayer_id': rfc,
'status': True,
}
result = self._get_result(client, 'add_token', args)
if self.error:
log.error(self.error)
return ''
if not result.success:
self.error = result.message
log.error(self.error)
return ''
return result.token
def client_add_timbres(self, rfc, credit):
"""Agregar credito a un emisor
Se requiere cuenta de reseller
Args:
rfc (str): El RFC del emisor, debe existir
credit (int): Cantidad de folios a agregar
Returns:
dict
'success': True or False,
'credit': nuevo credito despues de agregar or None
'message':
'Success, added {credit} of credit to {RFC}.'
'RFC no encontrado'
"""
auth = AUTH['RESELLER']
method = 'client'
client = Client(
self.URL[method], transport=self._transport, plugins=self._plugins)
args = {
'username': auth['user'],
'password': auth['pass'],
'taxpayer_id': rfc,
'credit': credit,
}
result = self._get_result(client, 'assign', args)
if self.error:
log.error(error)
return ''
if not result.success:
self.error = result.message
return 0
return result.credit
def client_balance(self, auth={}, rfc=''):
"""Regresa los timbres restantes del cliente
Se pueden usar las credenciales de relleser o las credenciales del emisor
Args:
auth (dict): Credenciales del emisor
rfc (str): El RFC del emisor
Returns:
int Cantidad de timbres restantes
"""
if not auth:
auth = AUTH['RESELLER']
method = 'client'
client = Client(self.URL[method],
transport=self._transport, plugins=self._plugins)
args = {
'reseller_username': auth['user'],
'reseller_password': auth['pass'],
'taxpayer_id': rfc,
}
result = self._get_result(client, 'get', args)
if self.error:
log.error(self.error)
return ''
success = bool(result.users)
if not success:
self._error = result.message or 'RFC no existe'
log.error(self.error)
return 0
return result.users.ResellerUser[0].credit
def client_set_status(self, rfc, status):
"""Edita el estatus (Activo o Suspendido) de un cliente
Se requiere cuenta de reseller para usar este método
Args:
rfc (str): El RFC del cliente
Kwargs:
status (bool):
True == 'A' == Activo
False == 'S' == Suspendido
Returns:
dict
'message':
'Account Created successfully'
'Account Already exists'
'success': True or False
"""
auth = AUTH['RESELLER']
ts = {True: 'A', False: 'S'}
method = 'client'
client = Client(self.URL[method],
transport=self._transport, plugins=self._plugins)
args = {
'reseller_username': auth['user'],
'reseller_password': auth['pass'],
'taxpayer_id': rfc,
'status': ts[status],
}
result = self._get_result(client, 'edit', args)
if self.error:
return False
if not result.success:
self.error = result.message
return False
return True
def client_switch(self, rfc, type_user):
"""Edita el tipo de timbrado (OnDemand o Prepago) de un cliente
Se requiere cuenta de reseller para usar este método
Args:
rfc (str): El RFC del cliente
Kwargs:
status (bool):
True == 'O' == OnDemand
False == 'P' == Prepago
Returns:
dict
'message':
'Account Created successfully'
'Account Already exists'
'success': True or False
"""
auth = AUTH['RESELLER']
tu = {True: 'O', False: 'P'}
method = 'client'
client = Client(self.URL[method],
transport=self._transport, plugins=self._plugins)
args = {
'username': auth['user'],
'password': auth['pass'],
'taxpayer_id': rfc,
'type_user': tu[type_user],
}
result = self._get_result(client, 'switch', args)
if self.error:
return False
if not result.success:
self.error = result.message
return False
return True
def client_report_folios(self, rfc, date_from, date_to, invoice_type='I'):
"""Obtiene un reporte del total de facturas timbradas
"""
auth = AUTH['RESELLER']
args = {
'username': auth['user'],
'password': auth['pass'],
'taxpayer_id': rfc,
'date_from': date_from,
'date_to': date_to,
'invoice_type': invoice_type,
}
method = 'util'
client = Client(self.URL[method],
transport=self._transport, plugins=self._plugins)
result = self._get_result(client, 'report_total', args)
if result.result is None:
# ~ PAC - Debería regresar RFC inexistente o sin registros
self.error = 'RFC no existe o no tiene registros'
return 0
total = result.result.ReportTotal[0].total
return total

View File

@ -0,0 +1,87 @@
#!/usr/bin/env python3
from decimal import Decimal, getcontext
# ~ getcontext().prec = 6
import lxml.etree as ET
from requests.structures import CaseInsensitiveDict as CIDict
NS_CFDI = {
'cfdi': 'http://www.sat.gob.mx/cfd/3',
'tfd': 'http://www.sat.gob.mx/TimbreFiscalDigital',
'nomina12': 'http://www.sat.gob.mx/nomina12',
}
PRE = '/cfdi:Comprobante'
class CfdiRead(object):
def __init__(self, source):
self._source = source
self._data = {}
self._error = ''
self._rfc_emisor = ''
self._rfc_receptor = ''
self._parse()
@property
def source(self):
return self._source
@property
def data(self):
return self._data
@property
def rfc_emisor(self):
return self._rfc_emisor
@property
def rfc_receptor(self):
return self._rfc_receptor
@property
def error(self):
return self._error
def _parse(self):
self._tree = ET.fromstring(self.source)
self._data['cfdi'] = dict(self._tree.attrib)
node_name = f'{PRE}/cfdi:Emisor'
self._data['emisor'] = self._get_attr(node_name)
self._rfc_emisor = self._data['emisor']['Rfc']
node_name = f'{PRE}/cfdi:Receptor'
self._data['receptor'] = self._get_attr(node_name)
self._rfc_receptor = self._data['receptor']['Rfc']
node_name = f'{PRE}/cfdi:Complemento/tfd:TimbreFiscalDigital'
self._data['timbre'] = self._get_attr(node_name)
self._parse_details()
return
def _get_attr(self, node_name):
node = self._tree.xpath(node_name, namespaces=NS_CFDI)[0]
attr = dict(node.attrib)
return attr
def _parse_details(self):
node_name = f'{PRE}/cfdi:Conceptos/cfdi:Concepto'
details = self._tree.xpath(node_name, namespaces=NS_CFDI)
rows = []
for detail in details:
row = dict(detail.attrib)
for k, v in row.items():
if k in ('Cantidad', 'ValorUnitario', 'Descuento', 'Importe'):
row[k] = Decimal(v)
# ~ row['taxes'] = self._get_taxes(detail)
rows.append(row)
self._data['conceptos'] = rows
return
class CfdiWrite(object):
pass

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,6 @@ from middleware import (
AuthMiddleware,
JSONTranslator,
ConnectionMiddleware,
static,
handle_404
)
from models.db import StorageEngine
@ -16,7 +15,18 @@ from controllers.main import (AppEmpresas,
AppLogin, AppLogout, AppAdmin, AppEmisor, AppConfig,
AppMain, AppValues, AppPartners, AppProducts, AppInvoices, AppFolios,
AppDocumentos, AppFiles, AppPreInvoices, AppCuentasBanco,
AppMovimientosBanco, AppTickets, AppStudents, AppEmployees, AppNomina
AppMovimientosBanco, AppTickets, AppStudents, AppEmployees, AppNomina,
AppInvoicePay, AppCfdiPay, AppSATBancos, AppSociosCuentasBanco,
AppSATFormaPago, AppSATLeyendaFiscales, AppCert, AppSucursales,
AppPartnerProducts,
AppInventoryEntries,
AppTicketsDetails,
AppUsers,
AppWareHouse,
AppWareHouseProduct,
AppSATUnidadesPeso,
AppSATRegimenes,
AppSociosRegimenes,
)
@ -55,11 +65,25 @@ api.add_route('/movbanco', AppMovimientosBanco(db))
api.add_route('/students', AppStudents(db))
api.add_route('/employees', AppEmployees(db))
api.add_route('/nomina', AppNomina(db))
api.add_route('/invoicepay', AppInvoicePay(db))
api.add_route('/cfdipay', AppCfdiPay(db))
api.add_route('/satbancos', AppSATBancos(db))
api.add_route('/satformapago', AppSATFormaPago(db))
api.add_route('/socioscb', AppSociosCuentasBanco(db))
api.add_route('/leyendasfiscales', AppSATLeyendaFiscales(db))
api.add_route('/cert', AppCert(db))
api.add_route('/sucursales', AppSucursales(db))
api.add_route('/partnerproducts', AppPartnerProducts(db))
api.add_route('/inventoryentries', AppInventoryEntries(db))
api.add_route('/warehouse', AppWareHouse(db))
api.add_route('/warehouseproduct', AppWareHouseProduct(db))
api.add_route('/ticketsdetails', AppTicketsDetails(db))
api.add_route('/users', AppUsers(db))
api.add_route('/satunidadespeso', AppSATUnidadesPeso(db))
api.add_route('/satregimenes', AppSATRegimenes(db))
api.add_route('/sociosregimenes', AppSociosRegimenes(db))
# ~ Activa si usas waitress y NO estas usando servidor web
# ~ api.add_sink(static, '/static')
session_options = {
'session.type': 'file',
'session.cookie_expires': True,

View File

@ -8,4 +8,4 @@ threads = 4
py-autoreload = 1
thunder-lock = true
static-map = /static=../static
http-timeout = 300
http-timeout = 300

View File

@ -3,7 +3,7 @@
import falcon
from controllers import util
from models import main
from settings import MV, PATH_STATIC
from settings import MV
def handle_404(req, resp):
@ -20,18 +20,21 @@ def get_template(req, resp, resource):
resp.body = util.get_template(resource.template, data)
def static(req, res):
path = PATH_STATIC + req.path
if util.is_file(path):
res.content_type = util.get_mimetype(path)
res.stream, res.stream_len = util.get_stream(path)
res.status = falcon.HTTP_200
else:
res.status = falcon.HTTP_404
# ~ def static(req, res):
# ~ path = PATH_STATIC + req.path
# ~ if util.is_file(path):
# ~ res.content_type = util.get_mimetype(path)
# ~ res.stream, res.stream_len = util.get_stream(path)
# ~ res.status = falcon.HTTP_200
# ~ else:
# ~ res.status = falcon.HTTP_404
class AuthMiddleware(object):
def process_response(self, req, resp, resource):
pass
def process_resource(self, req, resp, resource, params):
session = req.env['beaker.session']
user = session.get('userobj', None)
@ -65,9 +68,15 @@ class JSONTranslator(object):
def process_response(self, req, resp, resource):
if 'result' not in req.context:
return
if '/doc/' in req.path:
resp.body = req.context['result']
return
if 'blob' in req.context:
resp.body = req.context['blob']
return
resp.body = util.dumps(req.context['result'])

View File

@ -1,5 +1,21 @@
#!/usr/bin/env python
# ~ Empresa Libre
# ~ Copyright (C) 2016-2018 Mauricio Baeza Servin (web@correolibre.net)
# ~
# ~ This program is free software: you can redistribute it and/or modify
# ~ it under the terms of the GNU General Public License as published by
# ~ the Free Software Foundation, either version 3 of the License, or
# ~ (at your option) any later version.
# ~
# ~ This program is distributed in the hope that it will be useful,
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# ~ GNU General Public License for more details.
# ~
# ~ You should have received a copy of the GNU General Public License
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
from . import main
@ -17,30 +33,24 @@ class StorageEngine(object):
def get_nomina(self, values):
return main.CfdiNomina.get_by(values)
def nomina(self, values):
opt = values.pop('opt')
if opt == 'cancel':
return main.CfdiNomina.cancel(int(values['id']))
def empresa_agregar(self, values):
return main.empresa_agregar(values['alta_rfc'], False)
# ~ return main.empresa_agregar(values['alta_rfc'], False)
return main._new_client(values['alta_rfc'], False)
def empresa_borrar(self, values):
return main.empresa_borrar(values['rfc'])
# ~ return main.empresa_borrar(values['rfc'])
return main._delete_client(values['rfc'], False, False)
def respaldar_dbs(self):
return main.respaldar_dbs()
def _get_empresas(self, values):
return main.get_empresas()
def get_values(self, table, values=None, session=None):
if table in ('allusuarios', 'usuarioupdate'):
if table in ('allusuarios', 'usuarioupdate', 'main'):
return getattr(self, '_get_{}'.format(table))(values, session)
return getattr(self, '_get_{}'.format(table))(values)
def _get_timbres(self, values):
return main.get_timbres()
return main.Emisor.get_timbres()
def _get_schoolgroups(self, values):
return main.Grupos.get_by(values)
@ -60,8 +70,11 @@ class StorageEngine(object):
def _get_importinvoice(self, values):
return main.import_invoice()
def _get_main(self, values):
return main.config_main()
def _get_importceods(self, values):
return main.import_ceods()
def _get_main(self, values, session):
return main.config_main(session['userobj'])
def _get_configtimbrar(self, values):
return main.config_timbrar()
@ -110,12 +123,6 @@ class StorageEngine(object):
def enviar_prefac(self, values):
return main.PreFacturas.enviar(values['id'])
# ~ def _get_cancelinvoice(self, values):
# ~ return main.Facturas.cancel(values['id'])
def _get_statussat(self, values):
return main.Facturas.get_status_sat(values['id'])
def _get_verifysat(self, values):
return main.Facturas.get_verify_sat(values['id'])
@ -157,6 +164,9 @@ class StorageEngine(object):
def _get_unidades(self, values):
return main.SATUnidades.get_activos()
def _get_unitbykey(self, values):
return main.SATUnidades.get_activos_by_key()
def add_moneda(self, values):
return main.SATMonedas.add(values)
@ -193,6 +203,10 @@ class StorageEngine(object):
def _get_allusoscfdi(self, values):
return main.SATUsoCfdi.get_all()
def _get_allregimenes(self, values):
filters = {'opt': 'all'}
return main.SATRegimenes.get_data(filters, None)
def _get_allusuarios(self, values, session):
return main.Usuarios.get_(session['userobj'])
@ -220,6 +234,9 @@ class StorageEngine(object):
def _get_usocfdiupdate(self, values):
return main.SATUsoCfdi.actualizar(values)
def _get_regimenesupdate(self, values):
return main.SATRegimenes.actualizar(values)
def _get_emisorcuentasbanco(self, values):
return main.CuentasBanco.emisor()
@ -232,6 +249,9 @@ class StorageEngine(object):
def _get_satunidades(self, values):
return main.get_sat_unidades(values['key'])
def _get_satunidadespeso(self, values):
return main.get_sat_unidadespeso(values['key'])
def _get_satproductos(self, values):
return main.get_sat_productos(values['key'])
@ -256,13 +276,13 @@ class StorageEngine(object):
def _get_ebancomov(self, values):
return main.MovimientosBanco.con(values['id'])
def delete(self, table, id):
def delete(self, table, id, user=None):
if table == 'partner':
return main.Socios.remove(id)
if table == 'product':
return main.Productos.remove(id)
if table == 'invoice':
return main.Facturas.remove(id)
return main.Facturas.remove(id, user)
if table == 'folios':
return main.Folios.remove(id)
if table == 'preinvoice':
@ -338,6 +358,9 @@ class StorageEngine(object):
return main.Facturas.add(values, user)
def invoice_put(self, values, user):
return main.Facturas.put(values, user)
def preinvoice(self, values):
id = int(values.pop('id', '0'))
#~ if id:
@ -359,17 +382,19 @@ class StorageEngine(object):
if opt == 'add':
return main.Tickets.add(values, user)
if opt == 'cancel':
return main.Tickets.cancel(values)
return main.Tickets.cancel(values, user)
if opt == 'invoice':
return main.Tickets.invoice(values, user)
if opt == 'print':
return main.Tickets.printer(values)
def get_tickets(self, values):
return main.Tickets.get_by(values)
def get_tickets(self, values, user):
return main.Tickets.get_by(values, user)
def get_invoices(self, values):
return main.Facturas.get_(values)
def get_invoices(self, filters, user):
if filters.get('by', ''):
return main.Facturas.get_by(filters, user)
return main.Facturas.get_(filters)
def get_preinvoices(self, values):
return main.PreFacturas.get_(values)
@ -389,8 +414,8 @@ class StorageEngine(object):
def cuentasbanco(self, values):
return main.CuentasBanco.add(values)
def add_movbanco(self, values):
return main.MovimientosBanco.add(values)
# ~ def add_movbanco(self, values):
# ~ return main.MovimientosBanco.add(values)
def get_cuentasbanco(self, values):
return main.CuentasBanco.get_(values)
@ -412,3 +437,112 @@ class StorageEngine(object):
def importar_bdfl(self):
return main.importar_bdfl()
# ~ Revisado
def get_invoicepay(self, values):
return main.FacturasPagos.get_values(values)
def get_cfdipay(self, values):
return main.CfdiPagos.get_values(values)
def get_sat_bancos(self, values):
return main.SATBancos.get_values(values)
def get_sat_forma_pago(self, values):
return main.SATFormaPago.get_values(values)
def get_partners_accounts_bank(self, values):
return main.SociosCuentasBanco.get_values(values)
def cfdipay(self, values):
return main.CfdiPagos.post(values)
def bankmovement(self, values):
return main.MovimientosBanco.post(values)
def sat_bancos(self, values):
return main.SATBancos.post(values)
def sat_forma_pago(self, values):
return main.SATFormaPago.post(values)
def partners_accounts_bank(self, values):
return main.SociosCuentasBanco.post(values)
def nomina(self, values, user):
return main.CfdiNomina.post(values, user)
def sat_leyendas_fiscales_get(self, values):
return main.SATLeyendasFiscales.get_values(values)
def sat_leyendas_fiscales_post(self, values):
return main.SATLeyendasFiscales.post(values)
def sat_leyendas_fiscales_delete(self, values):
return main.SATLeyendasFiscales.remove(values)
# ~ v2
def cert_get(self, filters):
return main.Certificado.get_data(filters)
def cert_post(self, filters):
return main.Certificado.post(filters)
def sucursales_get(self, filters):
return main.Sucursales.get_data(filters)
def sucursales_post(self, filters):
return main.Sucursales.post(filters)
def partner_products_get(self, filters):
return main.PartnerProducts.get_data(filters)
def inventory_entries_get(self, filters):
return main.InventoryEntries.get_data(filters)
def inventory_entries_post(self, filters, user):
return main.InventoryEntries.post(filters, user)
def warehouse_get(self, filters):
return main.Almacenes.get_data(filters)
def warehouse_post(self, values, user):
return main.Almacenes.post(values, user)
def warehouseproduct_get(self, filters, user):
return main.WareHouseProduct.get_data(filters, user)
def warehouseproduct_post(self, filters, user):
return main.WareHouseProduct.post(filters, user)
def users_get(self, filters, user):
return main.Usuarios.get_data(filters, user)
def users_post(self, args, user):
return main.Usuarios.post(args, user)
def ticketsdetails_get(self, filters, user):
return main.TicketsDetalle.get_data(filters, user)
def products_get(self, filters, user):
return main.Productos.get_data(filters, user)
def nomina_get(self, filters, user):
return main.CfdiNomina.get_data(filters, user)
def sat_unidades_peso_get(self, filters, user):
return main.SATUnidadesPeso.get_data(filters, user)
def sat_unidades_peso_post(self, args, user):
return main.SATUnidadesPeso.post(args, user)
def sat_regimenes_get(self, filters, user):
return main.SATRegimenes.get_data(filters, user)
def socios_regimenes_get(self, filters, user):
return main.SociosRegimenes.get_data(filters, user)
# Companies only in MV
def _get_empresas(self, values):
return main.companies_get()

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,20 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# ~ Empresa Libre
# ~ Copyright (C) 2016-2018 Mauricio Baeza Servin (publico@cuates.net)
# ~
# ~ This program is free software: you can redistribute it and/or modify
# ~ it under the terms of the GNU General Public License as published by
# ~ the Free Software Foundation, either version 3 of the License, or
# ~ (at your option) any later version.
# ~
# ~ This program is distributed in the hope that it will be useful,
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# ~ GNU General Public License for more details.
# ~
# ~ You should have received a copy of the GNU General Public License
# ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
import logbook
import os
@ -12,17 +28,9 @@ from conf import DEBUG, MV, LOG_PATH
try:
from conf import DEFAULT_PASSWORD
except ImportError:
DEFAULT_PASSWORD = 'salgueiro3.3'
DEFAULT_PASSWORD = 'salgueiro4.0'
try:
from conf import SEAFILE_SERVER
except ImportError:
SEAFILE_SERVER = {}
try:
from conf import TITLE_APP
except ImportError:
TITLE_APP = 'Empresa Libre'
TITLE_APP = 'Empresa Libre'
try:
from conf import NO_HTTPS
@ -31,13 +39,24 @@ except ImportError:
DEBUG = DEBUG
VERSION = '1.9.0'
EMAIL_SUPPORT = ('soporte@empresalibre.net',)
VERSION = '2.3.2'
EMAIL_SUPPORT = ('soporte@empresalibre.mx',)
TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION)
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
COMPANIES = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'rfc.db'))
path_static = os.path.abspath(os.path.join(BASE_DIR, '..', 'static'))
path_docs = os.path.abspath(os.path.join(BASE_DIR, '..', 'docs'))
path_css = os.path.join(path_static, 'css')
path_img = os.path.join(path_static, 'img')
path_user_template = os.path.join(path_docs, 'templates')
path_user_logos = os.path.join(path_docs, 'logos')
# ~ PATH_STATIC = os.path.abspath(os.path.join(BASE_DIR, '..'))
PATH_STATIC = os.path.abspath(os.path.join(BASE_DIR, '..'))
PATH_TEMPLATES = os.path.abspath(os.path.join(BASE_DIR, '..', 'templates'))
PATH_MEDIA = os.path.abspath(os.path.join(BASE_DIR, '..', 'docs'))
@ -52,17 +71,19 @@ PATH_SESSIONS = {
IV = 'valores_iniciales.json'
INIT_VALUES = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', IV))
CT = 'cancel_template.xml'
TEMPLATE_CANCEL = os.path.abspath(os.path.join(PATH_TEMPLATES, CT))
# ~ CT = 'cancel_template.xml'
# ~ TEMPLATE_CANCEL = os.path.abspath(os.path.join(PATH_TEMPLATES, CT))
PATH_XSLT = os.path.abspath(os.path.join(BASE_DIR, '..', 'xslt'))
PATH_BIN = os.path.abspath(os.path.join(BASE_DIR, '..', 'bin'))
template_lookup = TemplateLookup(directories=[PATH_TEMPLATES],
PATH_TEMPLATES_USER = os.path.abspath(os.path.join(
BASE_DIR, '..', 'docs', 'templates'))
directories=[PATH_TEMPLATES, PATH_TEMPLATES_USER]
template_lookup = TemplateLookup(directories=directories,
input_encoding='utf-8',
output_encoding='utf-8')
LOG_PATH = 'empresalibre.log'
LOG_NAME = 'API'
LOG_LEVEL = 'INFO'
@ -104,12 +125,29 @@ if 'win' in sys.platform:
PATH_XMLSEC = os.path.join(PATH_BIN, 'xmlsec.exe')
PRE_DEFAULT = {
'CFDI': {'VERSION': '4.0', 'PRE': '{http://www.sat.gob.mx/cfd/4}'},
'NOMINA': {'VERSION': '1.2', 'PRE': '{http://www.sat.gob.mx/nomina12}'},
'PAGOS': {'VERSION': '2.0', 'PRE': '{http://www.sat.gob.mx/Pagos20}'},
'TIBRE': {'VERSION': '1.1', 'PRE': '{http://www.sat.gob.mx/TimbreFiscalDigital}'},
}
pre2 ='{http://www.sat.gob.mx/cfd/2}'
pre3 ='{http://www.sat.gob.mx/cfd/3}'
PRE_HISTORY = {
'CFDI': {'2.0': pre2, '2.2': pre2,
'3.0': pre3, '3.2': pre3, '3.3': pre3},
'NOMINA': {'1.1': '{http://www.sat.gob.mx/nomina}'},
'PAGOS': {'1.0': '{http://www.sat.gob.mx/Pagos}'},
}
PRE = {
'2.0': '{http://www.sat.gob.mx/cfd/2}',
'2.2': '{http://www.sat.gob.mx/cfd/2}',
'3.0': '{http://www.sat.gob.mx/cfd/3}',
'3.2': '{http://www.sat.gob.mx/cfd/3}',
'3.3': '{http://www.sat.gob.mx/cfd/3}',
'4.0': '{http://www.sat.gob.mx/cfd/4}',
'TIMBRE': '{http://www.sat.gob.mx/TimbreFiscalDigital}',
'DONATARIA': '{http://www.sat.gob.mx/donat}',
'INE': '{http://www.sat.gob.mx/ine}',
@ -117,13 +155,19 @@ PRE = {
'NOMINA': {
'1.1': '{http://www.sat.gob.mx/nomina}',
'1.2': '{http://www.sat.gob.mx/nomina12}',
}
},
'PAGOS': {
'1.0': '{http://www.sat.gob.mx/Pagos}',
}
}
CURRENT_CFDI = '3.3'
CURRENT_CFDI_NOMINA = '1.2'
# To delete
# ~ CURRENT_CFDI = '4.0'
# ~ CURRENT_CFDI_NOMINA = '1.2'
DECIMALES = 2
DECIMALES_TAX = 4
DECIMALES_PRECIOS = 4
IMPUESTOS = {
'ISR': '001',
'IVA': '002',
@ -138,6 +182,18 @@ IMPUESTOS = {
}
DEFAULT_SAT_PRODUCTO = '01010101'
DEFAULT_SERIE_TICKET = 'T'
DEFAULT_CFDIPAY = {
'SERIE': 'FP',
'TYPE': 'P',
'WAYPAY': 'PPD',
'CURRENCY': 'XXX',
'TC': '1',
'USED': 'CP01',
'KEYSAT': '84111506',
'UNITKEY': 'ACT',
'DESCRIPTION': 'Pago',
'TYPE_RELATION': '04',
}
DIR_FACTURAS = 'facturas'
USAR_TOKEN = False
CANCEL_SIGNATURE = False
@ -145,7 +201,7 @@ PUBLIC = 'Público en general'
DEFAULT_SAT_NOMINA = {
'SERIE': 'N',
'FORMA_PAGO': '99',
'USO_CFDI': 'P01',
'USO_CFDI': 'CN01',
'CLAVE': '84111505',
'UNIDAD': 'ACT',
'DESCRIPCION': 'Pago de nómina',
@ -153,3 +209,111 @@ DEFAULT_SAT_NOMINA = {
API = 'https://api.empresalibre.net{}'
CURRENCY_MN = 'MXN'
# ~ v2
CANCEL_VERSION = ('3.3', '4.0')
CFDI_VERSIONS = CANCEL_VERSION
IS_MV = MV
DB_COMPANIES = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'rfc.db'))
path_bk = os.path.join(path_docs, 'tmp')
path_local = 'facturas'
path_sat = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'valores_iniciales.json'))
EXT = {
'CSS': 'css',
'HTML': 'html',
'ODS': 'ods',
'PNG': 'png',
'JSON': 'json',
}
MXN = 'MXN'
CARTA_PORTE = {
'MONEDA': 'XXX',
}
PATHS = {
'STATIC': path_static,
'CSS': path_css,
'IMG': path_img,
'DOCS': path_docs,
'USER': path_user_template,
'LOGOS': path_user_logos,
'BK': path_bk,
'LOCAL': path_local,
'SAT': path_sat,
'xslt': PATH_XSLT,
}
VALUES_PDF = {
'CANCEL': {True: 'inline', False: 'none'},
'TYPE': {'I': 'Ingreso', 'E': 'Egreso', 'T': 'Traslado'},
'TAX': {'001': 'ISR', '002': 'IVA', '003': 'IEPS'},
'METHOD': {
'PUE': 'Pago en una sola exhibición',
'PPD': 'Pago en parcialidades o diferido',
},
}
RESICO = '626'
RFCS = {
'PUBLIC': 'XAXX010101000',
'FOREIGN': 'XEXX010101000',
'CVD110412TF6': 'finkok',
'SCD110105654': 'comercio',
'AAA010101AAA': 'comercio',
'SPR190613I52': 'comercio',
}
URL = {
'SEAFILE': 'https://seafile.cuates.net',
}
DEFAULT_GLOBAL = {
'cantidad': 1.00,
'unidad': 'ACT',
'descripcion': 'Venta',
'clave_sat': '01010101',
}
# ~ TEMPLATE_CANCEL = """<CancelaCFD xmlns="http://cancelacfd.sat.gob.mx">
# ~ <Cancelacion xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" RfcEmisor="{rfc}" Fecha="{fecha}">
# ~ <Folios>
# ~ <Folio UUID="{uuid}" Motivo="{motivo}"{folio}/>
# ~ </Folios>
# ~ <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
# ~ <SignedInfo>
# ~ <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
# ~ <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
# ~ <Reference URI="">
# ~ <Transforms>
# ~ <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
# ~ </Transforms>
# ~ <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
# ~ <DigestValue/>
# ~ </Reference>
# ~ </SignedInfo>
# ~ <SignatureValue/>
# ~ <KeyInfo>
# ~ <X509Data>
# ~ <X509IssuerSerial>
# ~ <X509IssuerName/>
# ~ <X509SerialNumber/>
# ~ </X509IssuerSerial>
# ~ <X509Certificate/>
# ~ </X509Data>
# ~ <KeyValue>
# ~ <RSAKeyValue>
# ~ <Modulus/>
# ~ <Exponent/>
# ~ </RSAKeyValue>
# ~ </KeyValue>
# ~ </KeyInfo>
# ~ </Signature>
# ~ </Cancelacion>
# ~ </CancelaCFD>"""
TEMPLATE_CANCEL = """<CancelaCFD xmlns="http://cancelacfd.sat.gob.mx"><Cancelacion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Fecha="{fecha}" RfcEmisor="{rfc}" xmlns="http://cancelacfd.sat.gob.mx"><Folios><Folio UUID="{uuid}" Motivo="{motivo}"{folio}/></Folios><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><DigestValue/></Reference></SignedInfo><SignatureValue/><KeyInfo><X509Data><X509IssuerSerial><X509IssuerName/><X509SerialNumber/></X509IssuerSerial><X509Certificate/></X509Data><KeyValue><RSAKeyValue><Modulus/><Exponent/></RSAKeyValue></KeyValue></KeyInfo></Signature></Cancelacion></CancelaCFD>"""

Binary file not shown.

Binary file not shown.

473
source/db/unidad_peso.csv Normal file
View File

@ -0,0 +1,473 @@
id key name
1 Tu Contenedor externo
2 X1A Tambor de acero
3 X1B Tambor de aluminio
4 X1D Tambor contrachapado
5 X1F Contenedor flexible
6 X1G Tambor de fibra
7 X1w Tambor de madera
8 X2C Barril de madera
9 X3A Bidón de acero
10 X3H Bidón de plástico
11 X43 Bolsa de gran tamaño
12 X44 Bolsa de plástico
13 X4A Caja de acero
14 X4B Caja de aluminio
15 X4C Caja de madera natural
16 X4D Caja de contrachapado
17 X4F Caja de madera reconstituida
18 X4G Caja de cartón
19 X4H Caja de plástico
20 X5H Bolsa de plástico tejido
21 X5L Bolsa textil
22 X5M Bolsa de papel
23 X6H Recipiente de plástico, Contenedor compuesto.
24 X6P Recipiente de vidrio, Contenedor compuesto.
25 X7A Estuche para carro
26 X7B Estuche de madera
27 X8A Pallet de madera
28 X8B Cajón de madera
29 X8C Madera flejada
30 XAA Contenedor intermedio para gráneles de plástico rígido
31 XAB Contenedor de fibra
32 XAC Contenedor de papel
33 XAD Contenedor de madera
34 XAE Aerosol
35 XAF Pallet modular con collares, 80cms * 60cms
36 XAG Pallet o empaquetado
37 XAH Pallet, 100cms X 110cms
38 XAI Contenedor tipo concha
39 XAJ Cono
40 XAL Esfera
41 XAM Ampolleta no protegida
42 XAP Ampolleta protegida
43 XAT Atomizador
44 XAV Cápsula
45 XB4 Cinturón
46 XBA Barril
47 XBB Bobina
48 XBC Cajón para botellas / Estante para botellas
49 XBD Tablero
50 XBE Flejado
51 XBF Globo no protegido
52 XBG Bolso
53 XBH Manojo
54 XBI Compartimiento
55 XBJ Cubeta
56 XBK Cesta
57 XBL Paca comprimida
58 XBM Cuenco
59 XBN Paca no comprimida
60 XBO Botella no-protegida y cilíndrica
61 XBP Globo protegido
62 XBQ Botella cilíndrica protegida
63 XBR Barra
64 XBS Botella, no-protegida en forma de bulbo
65 XBT Rollo de tela
66 XBU Butt
67 XBV Botella de bulbo protegido
68 XBW Caja para líquidos
69 XBX Caja
70 XBY Tablero, con fleje/ agrupados/ armados
71 XBZ Barras, con fleje/ agrupados/ armados
72 XCA Lata rectangular
73 XCB Cajón para cerveza
74 XCC Mantequera
75 XCD Lata con mango y boquilla
76 XCE Cesto tejido
77 XCF Cofre
78 XCG Contenedor tipo Jaula
79 XCH Cajonera
80 XCI Frasco
81 XCJ Ataúd
82 XCK Barrica
83 XCL Espiral
84 XCM Paquete de tarjetas
85 XCN Contenedor, no especificado como equipo de transporte
86 XCO Garrafón no protegido
87 XCP Garrafón protegido
88 XCQ Cartucho
89 XCR Cajón
90 XCS Estuche
91 XCT Cartón
92 XCU Vaso
93 XCV Cubierta
94 XCW Jaula estilo rodillo
95 XCX Lata cilíndrica
96 XCY Cilindro
97 XCZ Lona
98 XDA Cajón multicapa de plástico
99 XDB Cajón de varias capas de madera
100 XDC Cajón multicapa de cartón
101 XDG Jaula, Según la clasificación de la compañía (Commonwealth Handling Equipment Pool (CHEP))
102 XDH Caja, Según la clasificación de la compañía (CHEP), Eurobox
103 XDI Tambor de hierro
104 XDJ damajuana o garrafa, no protegido
105 XDK Cajón a granel, cartón
106 XDL Cajas de plástico
107 XDM Cajones a granel de madera
108 XDN Dispensador
109 XDP damajuana o garrafa, protegido
110 XDR Tambor
111 XDS Bandeja de una capa sin cubierta y de plástico
112 XDT Bandeja de una capa sin cubierta y de madera
113 XDU Bandeja de una capa sin cubierta y poliestireno
114 XDV Bandeja de una capa sin cubierta y de cartón
115 XDW Bandeja de dos capas sin tapa y con bandeja de plástico
116 XDX Bandeja de dos capas sin cubierta y de madera
117 XDY Bandeja de dos capas sin cubierta y de cartón
118 XEC Bolsa de plástico
119 XED Estuche, con pallet de base
120 XEE Estuche, con pallet base de madera
121 XEF Estuche, con pallet base de cartón
122 XEG Estuche, con pallet base de plástico
123 XEH Estuche, con pallet base de metal
124 XEI Estuche isotérmico
125 XEN Sobre
126 XFB Bolsa flexible
127 XFC Cajón para fruta
128 XFD Cajón enmarcado
129 XFE Tanque flexible
130 XFI Firkin
131 XFL Matraz
132 XFO Cajón para zapatos
133 XFP Caja auxiliar para película fotográfica
134 XFR Marco
135 XFT Contenedor para alimentos
136 XFW Carro de cama plana
137 XFX Bolsa flexible tipo contenedor
138 XGB Botella para gas
139 XGI Viga
140 XGL Contenedor tipo galón
141 XGR Recipiente de vidrio
142 XGU Bandeja contenedor para apilar horizontalmente objetos planos
143 XGY Costal de Yute
144 XGZ Vigas con correas o agrupadas
145 XHA Cesta con mango y de plástico
146 XHB Cesta con mango y de madera
147 XHC Cesta con asa y de cartón
148 XHG Hogshead
149 XHN Gancho
150 XHR Cesto
151 XIA Paquete con pantalla y de madera
152 XIB Paquete con pantalla y de cartón
153 XIC Paquete con pantalla y de plástico
154 XID Paquete con pantalla y de metal
155 XIE Paquete de mostrador.
156 XIF Envase para alimentos
157 XIG Paquete envuelto en papel
158 XIH Tambor de plástico
159 XIK Paquete de cartón con los agujeros para botellas
160 XIL Bandeja rígida con tapa y apilable (CEN TS 14482: 2002)
161 XIN Lingote
162 XIZ Lingotes con correas/ agrupados
163 XJB Bolsa jumbo
164 XJC Bidón rectangular
165 XJG Jarra
166 XJR Tarro
167 XJT Bolsa de yute
168 XJY Bidón, cilíndrico
169 XKG Barrilete
170 XKI Kit (Conjunto de piezas)
171 XLE Valijas
172 XLG Bitácora
173 XLT Lote
174 XLU Caja de arrastre
175 XLV Contenedor pequeño
176 XLZ Registros con fleje/ agrupados/ armados
177 XMA Cajón metálico
178 XMB Múltiplo de bolsas
179 XMC Cajón para leche
180 XME Contenedor de metal
181 XMR Recipiente de metal
182 XMS Saco milti-pared
183 XMT Tapete
184 XMW Contenedor envuelto en plástico
185 XMX Caja pequeña de cerillos
186 XNA No disponible
187 XNE Sin empaque o no empaquetado
188 XNF Sin empaque o no empaquetado, unidad simple
189 XNG Sin empaque o no empaquetado, unidades múltiples
190 XNS Caja nido
191 XNT Red
192 XNU Red de plástico con tubo
193 XNV Red textil con tubo
194 XOA Pallet, Según la clasificación de la compañía (Commonwealth Handling Equipment Pool (CHEP) 40 cm x 60 cm
195 XOB Pallet, Según la clasificación de la compañía (Commonwealth Handling Equipment Pool (CHEP) 80 cm x 120 cm
196 XOC Pallet, Según la clasificación de la compañía (Commonwealth Handling Equipment Pool (CHEP) 100 cm x 120 cm
197 XOD Pallet, AS 4068-1993
198 XOE Pallet, ISO T11
199 XOF Plataforma, peso o dimensión no especificada
200 XOK Bloque
201 XOT Octabin
202 XP2 Charola
203 XPA Cajetilla
204 XPB Pallet, Caja combinada y abierta con caja y pallet.
205 XPC Paquete postal
206 XPD Pallet modular con collares (80cms * 100cms)
207 XPE Pallet modular con collares (80cms * 120cms)
208 XPF Corral
209 XPG Placa
210 XPH Cantaro
211 XPI Pleca
212 XPJ Canastilla
213 XPK Paquete
214 XPL Balde
215 XPN Tablón
216 XPO Bolsa pequeña
217 XPR Contenedor de plástico
218 XPT Maceta
219 XPU Cacerola
220 XPV Tubos, con fleje/ agrupados/ armados
221 XPX Pallet
222 XPY Placas con fleje/ agrupados/ armados
223 XPZ Tablones con fleje/ agrupados/ armados
224 XQA Tambor de acero con cabeza no desmontable
225 XQB Tambor de acero con cabeza extraíble
226 XQC Tambor de aluminio con cabeza no extraíble
227 XQD Tambor de aluminio con cabeza extraíble
228 XQF Tambor, plástico con cabeza no desmontable
229 XQG Tambor, plástico, cabeza extraíble
230 XQH Barril de madera con tapón
231 XQJ Barril de madera con cabeza desprendible
232 XQK Bidón de acero con cabeza no desmontable
233 XQL Bidón de acero con cabeza desmontable
234 XQM Bidón de plástico con cabeza no desmontable
235 XQN Bidón de plástico con cabeza extraíble
236 XQP Caja de madera natural estándar
237 XQQ Caja de madera natural con muros a prueba de filtraciones
238 XQR Caja de plástico expandida
239 XQS Caja de plástico sólida
240 XRD Rod
241 XRG Anillo
242 XRJ Estante, Perchero para ropa
243 XRK Estante
244 XRL Carrete
245 XRO Rollo
246 XRT Red Roja
247 XRZ Varillas con fleje/ agrupados/ armados
248 XSA Saco
249 XSB Losa
250 XSC Cajón poco profundo
251 XSD Huso
252 XSE Baúl
253 XSH Bolsa pequeña hermética
254 XSI Patín
255 XSK Carcasa esqueleto
256 XSL Hoja de deslizamiento
257 XSM Hoja de metal
258 XSO Carrete pequeño
259 XSP Hoja de empaque de plástico
260 XSS Cajón de acero
261 XSU Maleta
262 XSV Sobre de acero
263 XSW Envoltorio
264 XSY Manga
265 XSZ Hojas con fleje/ agrupados/ armados
266 XT1 Tableta
267 XTB Tina
268 XTC Caja para té
269 XTD Tubo plegable
270 XTG Contenedor de tanque genérico
271 XTI Tierce
272 XTK Tanque rectangular
273 XTL Tina con tapa
274 XTN Hojalata
275 XTO Tonel
276 XTR Maletero
277 XTS Estructura
278 XTT Bolsa de mano
279 XTU Tubo
280 XTV Tubo con boquilla
281 XTW Pallet tricapa
282 XTY Tanque cilíndrico
283 XTZ Tubos con fleje/ agrupados/ armados
284 XUC Sin empaque
285 XUN Unidad
286 XVA Tanque
287 XVG Tanque de gas (a 1,031 mbar y 15° C)
288 XVI Frasco pequeño
289 XVK Paquete transportable
290 XVL Contenedor para líquidos a granel
291 XVN Vehículo
292 XVO "Contenedor para sólido de partículas grandes a granel (""nódulos"")"
293 XVP Envasado al vacío
294 XVQ Tanque para Gas licuado (a temperatura / presión anormal)
295 XVR Contenedor para sólidos de partículas granulares a granel (Granos)
296 XVS Contenedor de chatarra a granel
297 XVY "Contenedor para sólido de partículas finas a granel (""polvos"")"
298 XWA Contenedor de granel intermedio
299 XWB Botella de mimbre
300 XWC Contenedor intermedio para gráneles y de acero
301 XWD Contenedor intermedio para gráneles y de aluminio
302 XWF Contenedor intermedio para gráneles y de metal
303 XWG Contenedor intermedio para gráneles y de acero presurizado menor a 10 kpa
304 XWH Contenedor intermedio para gráneles y de aluminio, presurizado menor a 10 kpa
305 XWJ Contenedor intermedio para gráneles y de metal con una presión de 10 kpa
306 XWK Contenedor intermedio para gráneles y de acero para líquido
307 XWL Contenedor intermedio para gráneles y de aluminio para líquido
308 XWM Contenedor intermedio para gráneles y de metal para líquido
309 XWN Contenedor intermedio para gráneles con tejido plástico sin capa con revestimiento
310 XWP Contenedor intermedio para gráneles con tejido plástico y recubierto
311 XWQ Contenedor intermedio para gráneles con tejido plástico con revestimiento
312 XWR Contenedor intermedio para gráneles con tejido plástico, revestido y con forro
313 XWS Contenedor intermedio para gráneles con película de plástico
314 XWT Contenedor intermedio para gráneles textil sin capa / forro
315 XWU Contenedor intermedio para gráneles de madera natural con forro interior
316 XWV Contenedor intermedio para gráneles textil recubierto
317 XWW Contenedor intermedio para gráneles textil con revestimiento
318 XWX Contenedor intermedio para gráneles textil recubierto y con forro
319 XWY Contenedor intermedio para gráneles contrachapado con revestimiento interior
320 XWZ Contenedor intermedio para gráneles de madera reconstituida con revestimiento interior
321 XXA Bolsa de tejido plástico, sin abrigo interior ni forro
322 XXB Bolsa de tejido plástico a prueba de filtraciones
323 XXC Bolsa de tejido plástico resistente al agua
324 XXD Bolsa con película de plástico
325 XXF Bolsa textil sin capa ni forro interior
326 XXG Bolsa textil a prueba de filtraciones
327 XXH Bolsa textil resistente al agua
328 XXJ Bolsa de papel multi-pared
329 XXK Bolsa de papel multi-pared, resistente al agua
330 XYA Empaque compuesto, recipiente de plástico en tambor de acero
331 XYB Empaque compuesto, recipiente de plástico en cajas de acero
332 XYC Empaque compuesto, recipiente de plástico en tambor de aluminio
333 XYD Empaque compuesto, recipiente de plástico en cajón de aluminio
334 XYF Empaque compuesto, recipiente de plástico en caja de madera
335 XYG Empaque compuesto, recipiente de plástico en tambor de madera contrachapada
336 XYH Empaque compuesto, recipiente de plástico en caja de madera contrachapada
337 XYJ Empaque compuesto, recipiente de plástico en tambor de fibra
338 XYK Empaque compuesto, recipiente de plástico en caja de cartón
339 XYL Empaque compuesto, recipiente de plástico en el tambor de plástico
340 XYM Empaque compuesto, recipiente de plástico en caja de plástico sólido
341 XYN Empaque compuesto, receptáculo de vidrio en tambor de acero
342 XYP Empaque compuesto, receptáculo de vidrio en caja de cajas de acero
343 XYQ Empaque compuesto, recipiente de vidrio en tambor de aluminio
344 XYR Empaque compuesto, receptáculo de vidrio en caja de aluminio
345 XYS Empaque compuesto, recipiente de vidrio en caja de madera
346 XYT Empaque compuesto, recipiente de vidrio en tambor de madera contrachapada
347 Xyv Empaque compuesto, recipiente de vidrio en el cesto de mimbre
348 XYW Empaque compuesto, recipiente de vidrio en tambor de fibra
349 XYX Empaque compuesto, recipiente de vidrio en caja de cartón
350 XYY Empaque compuesto, recipiente de vidrio en paquete de plástico expandible
351 XYZ Empaque compuesto, recipiente de vidrio en paquete de plástico sólido
352 XZA Contenedor de granel intermedio, papel, multi-pared
353 XZB Bolsa grande
354 XZC Contenedor intermedio para gráneles de papel, multi-pared y resistente al agua
355 XZD Contenedor intermedio para gráneles de plástico rígido, con equipo estructural para sólidos
356 XZF Contenedor intermedio para gráneles de plástico rígido, autoportante para sólidos
357 XZG Contenedor intermedio para gráneles de plástico rígido, con equipo estructural, presurizado
358 XZH Contenedor intermedio para gráneles de plástico rígido, autoportante y presurizado
359 XZJ Contenedor intermedio para gráneles de plástico rígido, con equipo estructural para líquidos
360 XZK Contenedor intermedio para gráneles de plástico rígido, autoportante, líquidos
361 XZL Contenedor intermedio para gráneles, compuesto y de plástico rígido, sólidos
362 XZM Contenedor intermedio para gráneles, compuesto y de plástico flexible, sólidos
363 XZN Contenedor intermedio para gráneles, compuesto y de plástico rígido, presurizado
364 XZP Contenedor intermedio para gráneles, compuesto y de plástico flexible, presurizado
365 XZQ Contenedor intermedio para gráneles, compuesto y de plástico rígido, líquidos
366 XZR Contenedor intermedio para gráneles, compuesto y de plástico flexible para líquidos
367 XZS Contenedor intermedio para gráneles, compuesto
368 XZT Contenedor intermedio para gráneles con tablero de fibras
369 XZU Contenedor intermedio para gráneles flexible
370 XZV Contenedor intermedio para gráneles de metal, distinto del acero
371 XZW Contenedor intermedio para gráneles, de madera natural
372 XZX Contenedor intermedio para gráneles, de contrachapado
373 XZY Contenedor intermedio para gráneles, de madera reconstituida
374 KGM Kilogramo
375 MC Microgramo
376 DJ Decagramo
377 DG Decigramo
378 GRM Gramo
379 CGM Centigramo
380 TNE Tonelada (tonelada métrica)
381 DTN Decitonelada métrica
382 MGM Miligramo
383 HGM Hectogramo
384 KTN Kilotonelada Métrica
385 2U Megagramo
386 LBR Libra
387 GRN Grano
388 ONZ Onza (avoirdupois)
389 CWI Hundredweight
390 CWA Hundred pound
391 LTN Tonelada (UK) o tonelada larga (estados unidos)
392 STI Estone (UK)
393 STN Tonelada (estados unidos) o tonelada corta (UK y estados unidos)
394 APZ Onza troy u onza farmacéutica
395 F13 Slug
396 K64 Libra (avoirdupois) por grado fahrenheit
397 L69 Tonelada por kelvin
398 L87 Tonelada corta por grado fahrenheit
399 M85 Tonelada, ensayo
400 M86 Libra Alemana
401 J33 Microgramo por kilogramo
402 L32 Nanogramo por kilogramo
403 NA Miligramo por kilogramo
404 M29 Kilogramo por kilogramo
405 M91 Libra por libra
406 Q29 Microgramo por hectogramo
407 MTQ Metro cúbico
408 MAL Megalitro
409 LTR Litro
410 MMQ Milímetro cúbico
411 CMQ Centímetro cúbico
412 DMQ Decímetro cúbico
413 MLT Mililitro
414 HLT Hectolitro
415 CLT Centilitro
416 DMA Decámetro cúbico
417 H19 Hectómetro cúbico
418 H20 Kilómetro cúbico
419 M71 Metro cúbico por pascal (joules)
420 DLT Decilitro
421 4G Microlitro
422 K6 Kilolitro
423 A44 Decalitro
424 G94 Centímetro cúbico por bar
425 G95 Litro por bar
426 G96 Metro cúbico por bar
427 G97 Mililitro por bar
428 5I Pies cúbicos estándar
429 INQ Pulgada cúbica
430 FTQ Pie cúbico
431 YDQ Yarda cúbica
432 GLI Galón (UK)
433 GLL Galón (EUA)
434 PT Pinta (US)
435 PTI Pint (uk)
436 QTI Cuarto (UK)
437 PTL Pinta líquida (estados unidos)
438 QTL Cuarto de líquido (estadis unidos)
439 PTD Pinta seca (estados unidos)
440 OZI Onza líquida (UK)
441 QT Cuarto (EUA)
442 J57 Barril (uk petróleo)
443 K21 Pie cúbico por grado fahrenheit
444 K23 Pie cúbico por psi (libra por pulgada cuadrada)
445 L43 Peck (UK)
446 L61 Pinta (US seco)
447 L62 Cuarto de galón (seco de los EUA)
448 L84 Tonelada (flota UK)
449 L86 Tonelada (flota estados unidos)
450 M11 Yarda cúbica por grado fahrenheit
451 M14 Yarda cúbica por psi (libra por pulgada cuadrada)
452 OZA Onza líquida (estados unidos)
453 BUI Bushel (UK)
454 BUA Bushel (EUA)
455 BLL Barril (EUA)
456 BLD Barril seco (EUA)
457 GLD Galón seco (EUA)
458 QTD Cuarto seco (estados unidos)
459 G26 Estere
460 G21 Taza (unidad de volumen)
461 G24 Cucharada (estados unidos)
462 G25 Cucharilla (estados unidos)
463 G23 Peck
464 M67 Acre-pie
465 M68 Cordón
466 M69 Milla cúbica (reino unido)
467 M70 Unidad tradicional de capacidad de carga
468 Q32 Femtolitro
469 Q33 Picolitro
470 Q34 Nanolitro
471 NM3 Metro cúbico normalizado
472 SM3 Metro cúbico estándar
1 id key name
2 1 Tu Contenedor externo
3 2 X1A Tambor de acero
4 3 X1B Tambor de aluminio
5 4 X1D Tambor contrachapado
6 5 X1F Contenedor flexible
7 6 X1G Tambor de fibra
8 7 X1w Tambor de madera
9 8 X2C Barril de madera
10 9 X3A Bidón de acero
11 10 X3H Bidón de plástico
12 11 X43 Bolsa de gran tamaño
13 12 X44 Bolsa de plástico
14 13 X4A Caja de acero
15 14 X4B Caja de aluminio
16 15 X4C Caja de madera natural
17 16 X4D Caja de contrachapado
18 17 X4F Caja de madera reconstituida
19 18 X4G Caja de cartón
20 19 X4H Caja de plástico
21 20 X5H Bolsa de plástico tejido
22 21 X5L Bolsa textil
23 22 X5M Bolsa de papel
24 23 X6H Recipiente de plástico, Contenedor compuesto.
25 24 X6P Recipiente de vidrio, Contenedor compuesto.
26 25 X7A Estuche para carro
27 26 X7B Estuche de madera
28 27 X8A Pallet de madera
29 28 X8B Cajón de madera
30 29 X8C Madera flejada
31 30 XAA Contenedor intermedio para gráneles de plástico rígido
32 31 XAB Contenedor de fibra
33 32 XAC Contenedor de papel
34 33 XAD Contenedor de madera
35 34 XAE Aerosol
36 35 XAF Pallet modular con collares, 80cms * 60cms
37 36 XAG Pallet o empaquetado
38 37 XAH Pallet, 100cms X 110cms
39 38 XAI Contenedor tipo concha
40 39 XAJ Cono
41 40 XAL Esfera
42 41 XAM Ampolleta no protegida
43 42 XAP Ampolleta protegida
44 43 XAT Atomizador
45 44 XAV Cápsula
46 45 XB4 Cinturón
47 46 XBA Barril
48 47 XBB Bobina
49 48 XBC Cajón para botellas / Estante para botellas
50 49 XBD Tablero
51 50 XBE Flejado
52 51 XBF Globo no protegido
53 52 XBG Bolso
54 53 XBH Manojo
55 54 XBI Compartimiento
56 55 XBJ Cubeta
57 56 XBK Cesta
58 57 XBL Paca comprimida
59 58 XBM Cuenco
60 59 XBN Paca no comprimida
61 60 XBO Botella no-protegida y cilíndrica
62 61 XBP Globo protegido
63 62 XBQ Botella cilíndrica protegida
64 63 XBR Barra
65 64 XBS Botella, no-protegida en forma de bulbo
66 65 XBT Rollo de tela
67 66 XBU Butt
68 67 XBV Botella de bulbo protegido
69 68 XBW Caja para líquidos
70 69 XBX Caja
71 70 XBY Tablero, con fleje/ agrupados/ armados
72 71 XBZ Barras, con fleje/ agrupados/ armados
73 72 XCA Lata rectangular
74 73 XCB Cajón para cerveza
75 74 XCC Mantequera
76 75 XCD Lata con mango y boquilla
77 76 XCE Cesto tejido
78 77 XCF Cofre
79 78 XCG Contenedor tipo Jaula
80 79 XCH Cajonera
81 80 XCI Frasco
82 81 XCJ Ataúd
83 82 XCK Barrica
84 83 XCL Espiral
85 84 XCM Paquete de tarjetas
86 85 XCN Contenedor, no especificado como equipo de transporte
87 86 XCO Garrafón no protegido
88 87 XCP Garrafón protegido
89 88 XCQ Cartucho
90 89 XCR Cajón
91 90 XCS Estuche
92 91 XCT Cartón
93 92 XCU Vaso
94 93 XCV Cubierta
95 94 XCW Jaula estilo rodillo
96 95 XCX Lata cilíndrica
97 96 XCY Cilindro
98 97 XCZ Lona
99 98 XDA Cajón multicapa de plástico
100 99 XDB Cajón de varias capas de madera
101 100 XDC Cajón multicapa de cartón
102 101 XDG Jaula, Según la clasificación de la compañía (Commonwealth Handling Equipment Pool (CHEP))
103 102 XDH Caja, Según la clasificación de la compañía (CHEP), Eurobox
104 103 XDI Tambor de hierro
105 104 XDJ damajuana o garrafa, no protegido
106 105 XDK Cajón a granel, cartón
107 106 XDL Cajas de plástico
108 107 XDM Cajones a granel de madera
109 108 XDN Dispensador
110 109 XDP damajuana o garrafa, protegido
111 110 XDR Tambor
112 111 XDS Bandeja de una capa sin cubierta y de plástico
113 112 XDT Bandeja de una capa sin cubierta y de madera
114 113 XDU Bandeja de una capa sin cubierta y poliestireno
115 114 XDV Bandeja de una capa sin cubierta y de cartón
116 115 XDW Bandeja de dos capas sin tapa y con bandeja de plástico
117 116 XDX Bandeja de dos capas sin cubierta y de madera
118 117 XDY Bandeja de dos capas sin cubierta y de cartón
119 118 XEC Bolsa de plástico
120 119 XED Estuche, con pallet de base
121 120 XEE Estuche, con pallet base de madera
122 121 XEF Estuche, con pallet base de cartón
123 122 XEG Estuche, con pallet base de plástico
124 123 XEH Estuche, con pallet base de metal
125 124 XEI Estuche isotérmico
126 125 XEN Sobre
127 126 XFB Bolsa flexible
128 127 XFC Cajón para fruta
129 128 XFD Cajón enmarcado
130 129 XFE Tanque flexible
131 130 XFI Firkin
132 131 XFL Matraz
133 132 XFO Cajón para zapatos
134 133 XFP Caja auxiliar para película fotográfica
135 134 XFR Marco
136 135 XFT Contenedor para alimentos
137 136 XFW Carro de cama plana
138 137 XFX Bolsa flexible tipo contenedor
139 138 XGB Botella para gas
140 139 XGI Viga
141 140 XGL Contenedor tipo galón
142 141 XGR Recipiente de vidrio
143 142 XGU Bandeja contenedor para apilar horizontalmente objetos planos
144 143 XGY Costal de Yute
145 144 XGZ Vigas con correas o agrupadas
146 145 XHA Cesta con mango y de plástico
147 146 XHB Cesta con mango y de madera
148 147 XHC Cesta con asa y de cartón
149 148 XHG Hogshead
150 149 XHN Gancho
151 150 XHR Cesto
152 151 XIA Paquete con pantalla y de madera
153 152 XIB Paquete con pantalla y de cartón
154 153 XIC Paquete con pantalla y de plástico
155 154 XID Paquete con pantalla y de metal
156 155 XIE Paquete de mostrador.
157 156 XIF Envase para alimentos
158 157 XIG Paquete envuelto en papel
159 158 XIH Tambor de plástico
160 159 XIK Paquete de cartón con los agujeros para botellas
161 160 XIL Bandeja rígida con tapa y apilable (CEN TS 14482: 2002)
162 161 XIN Lingote
163 162 XIZ Lingotes con correas/ agrupados
164 163 XJB Bolsa jumbo
165 164 XJC Bidón rectangular
166 165 XJG Jarra
167 166 XJR Tarro
168 167 XJT Bolsa de yute
169 168 XJY Bidón, cilíndrico
170 169 XKG Barrilete
171 170 XKI Kit (Conjunto de piezas)
172 171 XLE Valijas
173 172 XLG Bitácora
174 173 XLT Lote
175 174 XLU Caja de arrastre
176 175 XLV Contenedor pequeño
177 176 XLZ Registros con fleje/ agrupados/ armados
178 177 XMA Cajón metálico
179 178 XMB Múltiplo de bolsas
180 179 XMC Cajón para leche
181 180 XME Contenedor de metal
182 181 XMR Recipiente de metal
183 182 XMS Saco milti-pared
184 183 XMT Tapete
185 184 XMW Contenedor envuelto en plástico
186 185 XMX Caja pequeña de cerillos
187 186 XNA No disponible
188 187 XNE Sin empaque o no empaquetado
189 188 XNF Sin empaque o no empaquetado, unidad simple
190 189 XNG Sin empaque o no empaquetado, unidades múltiples
191 190 XNS Caja nido
192 191 XNT Red
193 192 XNU Red de plástico con tubo
194 193 XNV Red textil con tubo
195 194 XOA Pallet, Según la clasificación de la compañía (Commonwealth Handling Equipment Pool (CHEP) 40 cm x 60 cm
196 195 XOB Pallet, Según la clasificación de la compañía (Commonwealth Handling Equipment Pool (CHEP) 80 cm x 120 cm
197 196 XOC Pallet, Según la clasificación de la compañía (Commonwealth Handling Equipment Pool (CHEP) 100 cm x 120 cm
198 197 XOD Pallet, AS 4068-1993
199 198 XOE Pallet, ISO T11
200 199 XOF Plataforma, peso o dimensión no especificada
201 200 XOK Bloque
202 201 XOT Octabin
203 202 XP2 Charola
204 203 XPA Cajetilla
205 204 XPB Pallet, Caja combinada y abierta con caja y pallet.
206 205 XPC Paquete postal
207 206 XPD Pallet modular con collares (80cms * 100cms)
208 207 XPE Pallet modular con collares (80cms * 120cms)
209 208 XPF Corral
210 209 XPG Placa
211 210 XPH Cantaro
212 211 XPI Pleca
213 212 XPJ Canastilla
214 213 XPK Paquete
215 214 XPL Balde
216 215 XPN Tablón
217 216 XPO Bolsa pequeña
218 217 XPR Contenedor de plástico
219 218 XPT Maceta
220 219 XPU Cacerola
221 220 XPV Tubos, con fleje/ agrupados/ armados
222 221 XPX Pallet
223 222 XPY Placas con fleje/ agrupados/ armados
224 223 XPZ Tablones con fleje/ agrupados/ armados
225 224 XQA Tambor de acero con cabeza no desmontable
226 225 XQB Tambor de acero con cabeza extraíble
227 226 XQC Tambor de aluminio con cabeza no extraíble
228 227 XQD Tambor de aluminio con cabeza extraíble
229 228 XQF Tambor, plástico con cabeza no desmontable
230 229 XQG Tambor, plástico, cabeza extraíble
231 230 XQH Barril de madera con tapón
232 231 XQJ Barril de madera con cabeza desprendible
233 232 XQK Bidón de acero con cabeza no desmontable
234 233 XQL Bidón de acero con cabeza desmontable
235 234 XQM Bidón de plástico con cabeza no desmontable
236 235 XQN Bidón de plástico con cabeza extraíble
237 236 XQP Caja de madera natural estándar
238 237 XQQ Caja de madera natural con muros a prueba de filtraciones
239 238 XQR Caja de plástico expandida
240 239 XQS Caja de plástico sólida
241 240 XRD Rod
242 241 XRG Anillo
243 242 XRJ Estante, Perchero para ropa
244 243 XRK Estante
245 244 XRL Carrete
246 245 XRO Rollo
247 246 XRT Red Roja
248 247 XRZ Varillas con fleje/ agrupados/ armados
249 248 XSA Saco
250 249 XSB Losa
251 250 XSC Cajón poco profundo
252 251 XSD Huso
253 252 XSE Baúl
254 253 XSH Bolsa pequeña hermética
255 254 XSI Patín
256 255 XSK Carcasa esqueleto
257 256 XSL Hoja de deslizamiento
258 257 XSM Hoja de metal
259 258 XSO Carrete pequeño
260 259 XSP Hoja de empaque de plástico
261 260 XSS Cajón de acero
262 261 XSU Maleta
263 262 XSV Sobre de acero
264 263 XSW Envoltorio
265 264 XSY Manga
266 265 XSZ Hojas con fleje/ agrupados/ armados
267 266 XT1 Tableta
268 267 XTB Tina
269 268 XTC Caja para té
270 269 XTD Tubo plegable
271 270 XTG Contenedor de tanque genérico
272 271 XTI Tierce
273 272 XTK Tanque rectangular
274 273 XTL Tina con tapa
275 274 XTN Hojalata
276 275 XTO Tonel
277 276 XTR Maletero
278 277 XTS Estructura
279 278 XTT Bolsa de mano
280 279 XTU Tubo
281 280 XTV Tubo con boquilla
282 281 XTW Pallet tricapa
283 282 XTY Tanque cilíndrico
284 283 XTZ Tubos con fleje/ agrupados/ armados
285 284 XUC Sin empaque
286 285 XUN Unidad
287 286 XVA Tanque
288 287 XVG Tanque de gas (a 1,031 mbar y 15° C)
289 288 XVI Frasco pequeño
290 289 XVK Paquete transportable
291 290 XVL Contenedor para líquidos a granel
292 291 XVN Vehículo
293 292 XVO Contenedor para sólido de partículas grandes a granel ("nódulos")
294 293 XVP Envasado al vacío
295 294 XVQ Tanque para Gas licuado (a temperatura / presión anormal)
296 295 XVR Contenedor para sólidos de partículas granulares a granel (Granos)
297 296 XVS Contenedor de chatarra a granel
298 297 XVY Contenedor para sólido de partículas finas a granel ("polvos")
299 298 XWA Contenedor de granel intermedio
300 299 XWB Botella de mimbre
301 300 XWC Contenedor intermedio para gráneles y de acero
302 301 XWD Contenedor intermedio para gráneles y de aluminio
303 302 XWF Contenedor intermedio para gráneles y de metal
304 303 XWG Contenedor intermedio para gráneles y de acero presurizado menor a 10 kpa
305 304 XWH Contenedor intermedio para gráneles y de aluminio, presurizado menor a 10 kpa
306 305 XWJ Contenedor intermedio para gráneles y de metal con una presión de 10 kpa
307 306 XWK Contenedor intermedio para gráneles y de acero para líquido
308 307 XWL Contenedor intermedio para gráneles y de aluminio para líquido
309 308 XWM Contenedor intermedio para gráneles y de metal para líquido
310 309 XWN Contenedor intermedio para gráneles con tejido plástico sin capa con revestimiento
311 310 XWP Contenedor intermedio para gráneles con tejido plástico y recubierto
312 311 XWQ Contenedor intermedio para gráneles con tejido plástico con revestimiento
313 312 XWR Contenedor intermedio para gráneles con tejido plástico, revestido y con forro
314 313 XWS Contenedor intermedio para gráneles con película de plástico
315 314 XWT Contenedor intermedio para gráneles textil sin capa / forro
316 315 XWU Contenedor intermedio para gráneles de madera natural con forro interior
317 316 XWV Contenedor intermedio para gráneles textil recubierto
318 317 XWW Contenedor intermedio para gráneles textil con revestimiento
319 318 XWX Contenedor intermedio para gráneles textil recubierto y con forro
320 319 XWY Contenedor intermedio para gráneles contrachapado con revestimiento interior
321 320 XWZ Contenedor intermedio para gráneles de madera reconstituida con revestimiento interior
322 321 XXA Bolsa de tejido plástico, sin abrigo interior ni forro
323 322 XXB Bolsa de tejido plástico a prueba de filtraciones
324 323 XXC Bolsa de tejido plástico resistente al agua
325 324 XXD Bolsa con película de plástico
326 325 XXF Bolsa textil sin capa ni forro interior
327 326 XXG Bolsa textil a prueba de filtraciones
328 327 XXH Bolsa textil resistente al agua
329 328 XXJ Bolsa de papel multi-pared
330 329 XXK Bolsa de papel multi-pared, resistente al agua
331 330 XYA Empaque compuesto, recipiente de plástico en tambor de acero
332 331 XYB Empaque compuesto, recipiente de plástico en cajas de acero
333 332 XYC Empaque compuesto, recipiente de plástico en tambor de aluminio
334 333 XYD Empaque compuesto, recipiente de plástico en cajón de aluminio
335 334 XYF Empaque compuesto, recipiente de plástico en caja de madera
336 335 XYG Empaque compuesto, recipiente de plástico en tambor de madera contrachapada
337 336 XYH Empaque compuesto, recipiente de plástico en caja de madera contrachapada
338 337 XYJ Empaque compuesto, recipiente de plástico en tambor de fibra
339 338 XYK Empaque compuesto, recipiente de plástico en caja de cartón
340 339 XYL Empaque compuesto, recipiente de plástico en el tambor de plástico
341 340 XYM Empaque compuesto, recipiente de plástico en caja de plástico sólido
342 341 XYN Empaque compuesto, receptáculo de vidrio en tambor de acero
343 342 XYP Empaque compuesto, receptáculo de vidrio en caja de cajas de acero
344 343 XYQ Empaque compuesto, recipiente de vidrio en tambor de aluminio
345 344 XYR Empaque compuesto, receptáculo de vidrio en caja de aluminio
346 345 XYS Empaque compuesto, recipiente de vidrio en caja de madera
347 346 XYT Empaque compuesto, recipiente de vidrio en tambor de madera contrachapada
348 347 Xyv Empaque compuesto, recipiente de vidrio en el cesto de mimbre
349 348 XYW Empaque compuesto, recipiente de vidrio en tambor de fibra
350 349 XYX Empaque compuesto, recipiente de vidrio en caja de cartón
351 350 XYY Empaque compuesto, recipiente de vidrio en paquete de plástico expandible
352 351 XYZ Empaque compuesto, recipiente de vidrio en paquete de plástico sólido
353 352 XZA Contenedor de granel intermedio, papel, multi-pared
354 353 XZB Bolsa grande
355 354 XZC Contenedor intermedio para gráneles de papel, multi-pared y resistente al agua
356 355 XZD Contenedor intermedio para gráneles de plástico rígido, con equipo estructural para sólidos
357 356 XZF Contenedor intermedio para gráneles de plástico rígido, autoportante para sólidos
358 357 XZG Contenedor intermedio para gráneles de plástico rígido, con equipo estructural, presurizado
359 358 XZH Contenedor intermedio para gráneles de plástico rígido, autoportante y presurizado
360 359 XZJ Contenedor intermedio para gráneles de plástico rígido, con equipo estructural para líquidos
361 360 XZK Contenedor intermedio para gráneles de plástico rígido, autoportante, líquidos
362 361 XZL Contenedor intermedio para gráneles, compuesto y de plástico rígido, sólidos
363 362 XZM Contenedor intermedio para gráneles, compuesto y de plástico flexible, sólidos
364 363 XZN Contenedor intermedio para gráneles, compuesto y de plástico rígido, presurizado
365 364 XZP Contenedor intermedio para gráneles, compuesto y de plástico flexible, presurizado
366 365 XZQ Contenedor intermedio para gráneles, compuesto y de plástico rígido, líquidos
367 366 XZR Contenedor intermedio para gráneles, compuesto y de plástico flexible para líquidos
368 367 XZS Contenedor intermedio para gráneles, compuesto
369 368 XZT Contenedor intermedio para gráneles con tablero de fibras
370 369 XZU Contenedor intermedio para gráneles flexible
371 370 XZV Contenedor intermedio para gráneles de metal, distinto del acero
372 371 XZW Contenedor intermedio para gráneles, de madera natural
373 372 XZX Contenedor intermedio para gráneles, de contrachapado
374 373 XZY Contenedor intermedio para gráneles, de madera reconstituida
375 374 KGM Kilogramo
376 375 MC Microgramo
377 376 DJ Decagramo
378 377 DG Decigramo
379 378 GRM Gramo
380 379 CGM Centigramo
381 380 TNE Tonelada (tonelada métrica)
382 381 DTN Decitonelada métrica
383 382 MGM Miligramo
384 383 HGM Hectogramo
385 384 KTN Kilotonelada Métrica
386 385 2U Megagramo
387 386 LBR Libra
388 387 GRN Grano
389 388 ONZ Onza (avoirdupois)
390 389 CWI Hundredweight
391 390 CWA Hundred pound
392 391 LTN Tonelada (UK) o tonelada larga (estados unidos)
393 392 STI Estone (UK)
394 393 STN Tonelada (estados unidos) o tonelada corta (UK y estados unidos)
395 394 APZ Onza troy u onza farmacéutica
396 395 F13 Slug
397 396 K64 Libra (avoirdupois) por grado fahrenheit
398 397 L69 Tonelada por kelvin
399 398 L87 Tonelada corta por grado fahrenheit
400 399 M85 Tonelada, ensayo
401 400 M86 Libra Alemana
402 401 J33 Microgramo por kilogramo
403 402 L32 Nanogramo por kilogramo
404 403 NA Miligramo por kilogramo
405 404 M29 Kilogramo por kilogramo
406 405 M91 Libra por libra
407 406 Q29 Microgramo por hectogramo
408 407 MTQ Metro cúbico
409 408 MAL Megalitro
410 409 LTR Litro
411 410 MMQ Milímetro cúbico
412 411 CMQ Centímetro cúbico
413 412 DMQ Decímetro cúbico
414 413 MLT Mililitro
415 414 HLT Hectolitro
416 415 CLT Centilitro
417 416 DMA Decámetro cúbico
418 417 H19 Hectómetro cúbico
419 418 H20 Kilómetro cúbico
420 419 M71 Metro cúbico por pascal (joules)
421 420 DLT Decilitro
422 421 4G Microlitro
423 422 K6 Kilolitro
424 423 A44 Decalitro
425 424 G94 Centímetro cúbico por bar
426 425 G95 Litro por bar
427 426 G96 Metro cúbico por bar
428 427 G97 Mililitro por bar
429 428 5I Pies cúbicos estándar
430 429 INQ Pulgada cúbica
431 430 FTQ Pie cúbico
432 431 YDQ Yarda cúbica
433 432 GLI Galón (UK)
434 433 GLL Galón (EUA)
435 434 PT Pinta (US)
436 435 PTI Pint (uk)
437 436 QTI Cuarto (UK)
438 437 PTL Pinta líquida (estados unidos)
439 438 QTL Cuarto de líquido (estadis unidos)
440 439 PTD Pinta seca (estados unidos)
441 440 OZI Onza líquida (UK)
442 441 QT Cuarto (EUA)
443 442 J57 Barril (uk petróleo)
444 443 K21 Pie cúbico por grado fahrenheit
445 444 K23 Pie cúbico por psi (libra por pulgada cuadrada)
446 445 L43 Peck (UK)
447 446 L61 Pinta (US seco)
448 447 L62 Cuarto de galón (seco de los EUA)
449 448 L84 Tonelada (flota UK)
450 449 L86 Tonelada (flota estados unidos)
451 450 M11 Yarda cúbica por grado fahrenheit
452 451 M14 Yarda cúbica por psi (libra por pulgada cuadrada)
453 452 OZA Onza líquida (estados unidos)
454 453 BUI Bushel (UK)
455 454 BUA Bushel (EUA)
456 455 BLL Barril (EUA)
457 456 BLD Barril seco (EUA)
458 457 GLD Galón seco (EUA)
459 458 QTD Cuarto seco (estados unidos)
460 459 G26 Estere
461 460 G21 Taza (unidad de volumen)
462 461 G24 Cucharada (estados unidos)
463 462 G25 Cucharilla (estados unidos)
464 463 G23 Peck
465 464 M67 Acre-pie
466 465 M68 Cordón
467 466 M69 Milla cúbica (reino unido)
468 467 M70 Unidad tradicional de capacidad de carga
469 468 Q32 Femtolitro
470 469 Q33 Picolitro
471 470 Q34 Nanolitro
472 471 NM3 Metro cúbico normalizado
473 472 SM3 Metro cúbico estándar

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
@license
webix UI v.5.0.0
webix UI v.5.4.3
This software is covered by Webix Commercial License.
Usage without proper license is prohibited.
(c) XB Software Ltd.
@ -9,12 +9,12 @@ Usage without proper license is prohibited.
.webix_view.webix_form{background-color:#fff}
body{-webkit-tap-highlight-color:transparent!important}
.webix_abslayout{position:relative}
.webix_abslayout>.webix_view{position:absolute}
.webix_abslayout>.webix_view{position:absolute!important}
.webix_layout_space,.webix_layout_wide{background-color:#ebebeb}
.webix_layout_accordion,.webix_layout_clean,.webix_layout_line,.webix_multiview{background:0 0}
.webix_overlay{width:100%;height:100%;position:absolute;z-index:10;text-align:center;padding-top:10px}
.webix_view>.webix_disabled{width:100%;height:100%;position:absolute;top:0;left:0;background-color:#ddd;opacity:.4;filter:alpha(opacity=40);z-index:1}
.webix_disabled_view{overflow:hidden!important}
.webix_disabled_view{overflow:hidden!important;position:relative}
body.webix_full_screen{margin:0;padding:0;overflow:hidden}
.webix_noselect,.webix_noselect div{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}
.webix_selectable{-moz-user-select:text;-webkit-user-select:text;user-select:text}
@ -25,38 +25,38 @@ body.webix_full_screen{margin:0;padding:0;overflow:hidden}
.webix_section>.webix_template{padding:0 8px;background-color:#fff;display:inline}
.webix_layout_space>.webix_section>.webix_template,.webix_layout_wide>.webix_section>.webix_template{padding:0 8px;background-color:#ebebeb}
.webix_layout_clean>.webix_section>.webix_template,.webix_layout_line>.webix_section>.webix_template{padding:0 8px;background-color:#fff}
.webix_header>div{padding-left:10px;font-family:Helvetica,Verdana;font-size:13px;font-weight:700;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);line-height:32px;line-height:34px;padding-top:0;padding-bottom:0}
.webix_header>div{padding-left:10px;font-family:Helvetica,Verdana;color:#1e2022;font-size:13px;font-weight:700;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x;line-height:32px;line-height:34px;padding-top:0;padding-bottom:0}
.webix_header>div .webix_el_label,.webix_header>div .webix_inp_label{color:#1e2022}
.webix_spacer{background:0 0}
.webix_view_animate{position:relative;width:100%;height:100%}
x\:ui{display:none}
.webix_flexlayout{display:flex!important;flex-wrap:wrap;flex-direction:row;overflow:hidden;box-sizing:border-box}
.webix_view.webix_flexlayout{display:flex!important;flex-wrap:wrap;flex-direction:row;overflow:hidden;box-sizing:border-box}
.webix_flexlayout>div{display:block!important}
.webix_view_align{background:0 0}
.webix_view a.webix_list_item,.webix_view div,.webix_view span{outline:0}
.webix_view a.webix_list_item:focus,.webix_view div:focus,.webix_view span:focus,.webix_view.webix_window:focus{outline:#727981 dotted 1px}
.webix_view a.webix_list_item:focus,.webix_view div:focus,.webix_view span:focus,.webix_view.webix_window:focus{outline-color:#727981;outline-style:dotted;outline-width:1px}
.webix_view div.webix_inp_static:focus,button,input,select,textarea{outline:0}
.webix_resize_area{position:absolute;top:0;left:0;width:100%;height:100%}
.webix_resize_handle_x .webix_handle_content,.webix_resize_handle_y .webix_handle_content{width:100%;height:100%;background:rgba(100,100,100,.1);border:1px dotted #9fa5aa}
.webix_resize_handle_x{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:e-resize;width:1px;height:100%;position:absolute;z-index:2;top:0}
.webix_resize_handle_x{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:ew-resize;width:1px;height:100%;position:absolute;z-index:2;top:0}
.webix_resize_handle_x .webix_handle_content{border-width:0 1px}
.webix_resize_origin_x{cursor:e-resize;width:3px;height:100%;position:absolute;z-index:2;top:0}
.webix_resize_handle_y{cursor:n-resize;height:1px;width:100%;position:absolute;z-index:2;left:0}
.webix_resize_origin_x{cursor:ew-resize;width:3px;height:100%;position:absolute;z-index:2;top:0}
.webix_resize_handle_y{cursor:ns-resize;height:1px;width:100%;position:absolute;z-index:2;left:0}
.webix_resize_handle_y .webix_handle_content{border-width:1px 0}
.webix_resize_origin_y{cursor:n-resize;height:3px;width:100%;position:absolute;z-index:2;left:0}
.webix_resize_origin_y{cursor:ns-resize;height:3px;width:100%;position:absolute;z-index:2;left:0}
.webix_resizer.webix_disabled_view{cursor:default}
.webix_resizer_vy{cursor:n-resize;margin-top:0!important;border:0!important;padding:0!important;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAADAQMAAABCowZuAAAABlBMVEUAAACkvtSA7tmIAAAAAXRSTlMAQObYZgAAAA9JREFUCB1jXMUABoxAGgAJaAFXPIkJqAAAAABJRU5ErkJggg==) center center no-repeat}
.webix_resizer_vx{cursor:e-resize;margin-left:0!important;border:0!important;padding:0!important;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAXAQMAAAD0oWdxAAAABlBMVEUAAACkvtSA7tmIAAAAAXRSTlMAQObYZgAAAA5JREFUeF5jWMDAQDwGAKyuB4FpGQdzAAAAAElFTkSuQmCC) center center no-repeat}
.webix_resizer_y{cursor:n-resize;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAADAQMAAABCowZuAAAABlBMVEUAAACkvtSA7tmIAAAAAXRSTlMAQObYZgAAAA9JREFUCB1jXMUABoxAGgAJaAFXPIkJqAAAAABJRU5ErkJggg==) center center no-repeat #fff}
.webix_resizer_x{cursor:e-resize;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAXAQMAAAD0oWdxAAAABlBMVEUAAACkvtSA7tmIAAAAAXRSTlMAQObYZgAAAA5JREFUeF5jWMDAQDwGAKyuB4FpGQdzAAAAAElFTkSuQmCC) center center no-repeat #fff}
.webix_resizer_vy{cursor:ns-resize;margin-top:0!important;border:0!important;padding:0!important;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAADAQMAAABCowZuAAAABlBMVEUAAACkvtSA7tmIAAAAAXRSTlMAQObYZgAAAA9JREFUCB1jXMUABoxAGgAJaAFXPIkJqAAAAABJRU5ErkJggg==) no-repeat center center}
.webix_resizer_vx{cursor:ew-resize;margin-left:0!important;border:0!important;padding:0!important;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAXAQMAAAD0oWdxAAAABlBMVEUAAACkvtSA7tmIAAAAAXRSTlMAQObYZgAAAA5JREFUeF5jWMDAQDwGAKyuB4FpGQdzAAAAAElFTkSuQmCC) no-repeat center center}
.webix_resizer_y{cursor:ns-resize;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAADAQMAAABCowZuAAAABlBMVEUAAACkvtSA7tmIAAAAAXRSTlMAQObYZgAAAA9JREFUCB1jXMUABoxAGgAJaAFXPIkJqAAAAABJRU5ErkJggg==) no-repeat center center;background-color:#fff}
.webix_resizer_x{cursor:ew-resize;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAXAQMAAAD0oWdxAAAABlBMVEUAAACkvtSA7tmIAAAAAXRSTlMAQObYZgAAAA5JREFUeF5jWMDAQDwGAKyuB4FpGQdzAAAAAElFTkSuQmCC) no-repeat center center;background-color:#fff}
.webix_accordionitem_body{position:relative}
.webix_accordionitem_header{border-bottom:1px solid #a4bed4;position:relative;z-index:2;font-family:Helvetica,Verdana;font-size:13px;font-weight:700;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);line-height:32px;cursor:pointer;overflow:hidden}
.webix_accordionitem_header{border-bottom:1px solid #a4bed4;position:relative;z-index:2;font-family:Helvetica,Verdana;color:#1e2022;font-size:13px;font-weight:700;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x;line-height:32px;cursor:pointer;overflow:hidden}
.webix_accordionitem_header .webix_el_label,.webix_accordionitem_header .webix_inp_label{color:#1e2022}
.webix_ie.horizontal>.webix_accordionitem_header.collapsed{-ms-writing-mode:tb-lr}
.webix_ie.horizontal>.webix_accordionitem_header.collapsed .webix_accordionitem_label{padding-left:0;padding-top:10px}
.webix_ie.horizontal>.webix_accordionitem_header.collapsed .webix_accordionitem_button{margin:0}
.webix_accordionitem_label{height:100%;padding-left:10px}
.webix_accordionitem_button{float:right;position:relative;height:11px;width:11px;margin:14px}
.webix_accordionitem_button{float:right;position:relative;height:11px;width:11px;margin:14px 14px}
.webix_carousel{position:relative}
.webix_nav_panel{bottom:15px;height:auto;line-height:8px;overflow:hidden;position:absolute;text-align:center}
.webix_nav_item{display:inline-block;height:8px;padding:6px 5px 6px 4px;width:8px;cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}
@ -89,10 +89,10 @@ x\:ui{display:none}
.webix_dark .webix_nav_button_side.webix_nav_button_next .webix_nav_button_inner{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAiCAYAAACwaJKDAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gcdCSE1IU5u4gAAAW1JREFUSMet1rtOwzAUgOG/5jbBwsQD8BAwIAa2TggegjmRgELbuFeo1GRlQEJMMDN264CUiYdgg0dolzIkFUEk9nHSbLGtT76cc+xaMA53gUegDnwCgfa9Vyp8CngCToFNYB940WF0WRWt57SPqsAK+C7oG+kwuiqLdg3992Xgtelk8jGN4w3gqGDMyTSOZ8eHB+8uM0X7XhMYGMbd6TC6dkIzcH8VsMr+aN9rCeCGEyqEhzZY5TWmcM8C3zihKdy2wIMiWJmWURZWtk1P4a4FvnVCUziwwP0srKQBLYSbALXFYuGU1zqMNBAYhrRUiSI0s/RvKcdZNoChcQt8Tz5TKSg/fQdQFqdJcJvAXha0Z1QCDixgW577drCbBxZXKRkYyOtpkm6lwf+VPwH7VcC/d5Qd7EjA39s0KQQ2UIvvfbZ3zoEHU2Rp3+u4vlDGqwSX6N4qwSX6ltMelAUB1oELYA6cAV/poTxXeZ/+AOFqn1e/Gh7yAAAAAElFTkSuQmCC)}
.webix_list_item{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:2px 10px;line-height:23px;cursor:pointer;border-bottom:1px solid #ebebeb;text-align:left}
.webix_list_item.webix_invalid{background-color:#fee}
.webix_list_item.webix_selected{color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background:-webkit-linear-gradient(#ffebc2,#ffdb8f);background:-moz-linear-gradient(#ffebc2,#ffdb8f);background:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_list_item.webix_selected{background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_list .webix_list_item.webix_selected{border-bottom:1px solid #ffd47b;box-shadow:0 1px #ffe3a9 inset;padding:2px 10px}
.webix_group{position:relative}
.webix_group_back,.webix_group_back.webix_selected{position:relative;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%)}
.webix_group_back,.webix_group_back.webix_selected{position:relative;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x}
.webix_arrow_icon{position:absolute;top:50%;bottom:50%;margin-top:-12px;right:15px;width:9px;height:22px;line-height:22px;color:#1e2022;font-size:18px;font-family:FontAwesome}
.webix_arrow_icon:before{content:'\f105'}
.webix_group_back{padding-left:29px}
@ -103,18 +103,19 @@ x\:ui{display:none}
.webix_unit_header{padding:0 10px;line-height:19px;text-align:left;background-color:#d6e8ff}
.webix_list-x .webix_list_item{display:inline-block;vertical-align:top;border-right:1px solid #ebebeb;border-bottom:none}
.webix_list-x .webix_list_item.webix_selected{border-right:1px solid #ffd47b;border-left:1px solid #ffd47b;padding-left:9px}
.webix_list-x .webix_scroll_cont{display:inline}
.webix_list-x .webix_scroll_cont{display:inline-block;overflow:visible}
.webix_view.webix_list-x{white-space:nowrap}
.webix_list_item.webix_disabled{color:#8b949e}
.webix_list_item.webix_disabled .webix_submenu_icon{visibility:hidden}
.webix_view.webix_pager{padding:2px 0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:transparent}
.webix_pager_item,.webix_pager_item_selected{padding:0 6px;text-align:center;height:100%;width:32px;border:1px solid #a4bed4;margin:0 2px;cursor:pointer;background-color:#fff;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:Helvetica,Verdana;font-size:13px}
.webix_pager_item,.webix_pager_item_selected{padding:0 6px;text-align:center;height:100%;width:auto;min-width:32px;border:1px solid #a4bed4;margin:0 2px;cursor:pointer;background-color:#fff;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:Helvetica,Verdana;font-size:13px}
.webix_pager_item_selected{cursor:default;background-color:#ffdb8f;border:1px solid #ffd47b}
.webix_animation .webix_ss_header{position:relative;z-index:10}
.webix_animation .webix_ss_footer,.webix_animation .webix_vscroll_x{position:absolute;bottom:0;z-index:10}
.webix_allow_selection{-moz-user-select:text;-webkit-user-select:text;user-select:text}
.webix_dataview_item{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:2px 10px;line-height:23px;cursor:pointer;border-bottom:1px solid #ebebeb;text-align:left;border-right:1px solid #ebebeb}
.webix_dataview_item.webix_selected{color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background:-webkit-linear-gradient(#ffebc2,#ffdb8f);background:-moz-linear-gradient(#ffebc2,#ffdb8f);background:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background:-o-linear-gradient(top,#ffebc2,#ffdb8f);border-bottom:1px solid #ffd47b;border-right:1px solid #ffd47b}
.webix_dataview_item.webix_selected{background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f);border-bottom:1px solid #ffd47b;border-right:1px solid #ffd47b}
.webix_dataview_item.webix_invalid{background-color:#fee}
.webix_chart{position:relative;font-family:Helvetica,Verdana;font-size:13px;color:#1e2022;overflow:hidden;z-index:1}
.webix_chart canvas{position:absolute}
.webix_canvas_text{position:absolute;text-align:center;overflow:hidden;white-space:nowrap;font-size:12px;z-index:100}
@ -155,11 +156,11 @@ x\:ui{display:none}
.webix_dt_editor select{padding-right:0;padding-left:5px}
.webix_clipbuffer{width:2000px;height:1px;padding:0;margin:0;border:0;left:0;top:0;white-space:pre-wrap;position:fixed;filter:alpha(opacity=0);opacity:0;pointer-events:none;cursor:default}
.webix_message_area{position:fixed;right:5px;width:250px;z-index:1000}
.webix_info{min-width:120px;font-family:Tahoma,Arial;z-index:10000;overflow:hidden;margin:5px 5px 10px;-webkit-transition:all .5s ease;-moz-transition:all .5s ease;-o-transition:all .5s ease;transition:all .5s ease}
.webix_info{min-width:120px;font-family:Tahoma,Arial;z-index:10000;overflow:hidden;margin:5px;margin-bottom:10px;-webkit-transition:all .5s ease;-moz-transition:all .5s ease;-o-transition:all .5s ease;transition:all .5s ease}
.webix_no_transition{-webkit-transition:none;-moz-transition:none;transition:none}
.webix_info.hidden{height:0;min-height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:0;margin-bottom:0;overflow:hidden}
.webix_modal_box{overflow:hidden;display:inline-block;min-width:250px;width:250px;text-align:center;position:fixed;background-color:#fff;box-shadow:0 3px 6px #c8c8c8;font-family:Helvetica,Verdana;z-index:20000;border-radius:0;outline:0}
.webix_popup_title{border-top-left-radius:-1px;border-top-right-radius:-1px;border-width:0}
.webix_popup_title{border-top-left-radius:-1px;border-top-right-radius:-1px;border-width:0;background-image:-webkit-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 97%,#393939 97%);background-image:-moz-linear-gradient(top,#707070 1%,#3d3d3d 70%,#4c4c4c 97%,#393939 97%)}
.webix_button,.webix_info,.webix_popup_button{cursor:pointer}
.webix_popup_text{overflow:hidden}
.webix_popup_controls{border-radius:6px;padding:5px 10px 10px}
@ -171,12 +172,12 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_alert_error .webix_popup_title,.webix_confirm_error .webix_popup_title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAsCAIAAAArRUU2AAAATklEQVR4nIWLuw2AMBBDjVuQiBT2oWbRDATrnB0KQOJoqPzRe3BrHI6dcBASYREKovtK6/6DsDOX+stN+3H1YX9ciRgnYq5EWYhS2dftBIuLT4JyIrPCAAAAAElFTkSuQmCC)}
.webix_alert_error,.webix_confirm_error{border:1px solid red}
.webix_button,.webix_popup_button{border:1px solid #a4bed4}
.webix_button input,.webix_popup_button div{font-size:13px;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background:-webkit-linear-gradient(#fff,#e6e6e6);background:-moz-linear-gradient(#fff,#e6e6e6);background:-ms-linear-gradient(top,#fff,#e6e6e6);background:-o-linear-gradient(top,#fff,#e6e6e6);height:28px;line-height:28px}
.webix_popup_button.confirm div{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%)}
.webix_button input,.webix_popup_button div{font-size:13px;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background-image:-webkit-linear-gradient(#fff,#e6e6e6);background-image:-moz-linear-gradient(#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);height:28px;line-height:28px}
.webix_popup_button.confirm div{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x}
.webix_popup_title{color:#fff;height:40px;line-height:40px}
.webix_popup_text{margin:0 0 5px;padding-top:25px;font-size:13px;color:#1e2022;min-height:60px}
.webix_popup_text{margin:0 0 5px 0;padding-top:25px;font-size:13px;color:#1e2022;min-height:60px}
.webix_error,.webix_info{font-size:13px;color:#333;box-shadow:0 0 10px #888;padding:0;background-color:#FFF;border-radius:3px;border:1px solid #fff}
.webix_info div{padding:5px 10px;background-color:#fff;border-radius:3px;border:1px solid #B8B8B8}
.webix_info div{padding:5px 10px 5px 10px;background-color:#fff;border-radius:3px;border:1px solid #B8B8B8}
.webix_error{background-color:#d81b1b;border:1px solid #ff3c3c;box-shadow:0 0 10px #000}
.webix_error div{background-color:#d81b1b;border:1px solid #940000;color:#FFF}
.webix_drag_zone{position:absolute;box-shadow:1px 1px 5px #a4bed4;background-color:#fff;font-family:Helvetica,Verdana;font-size:13px;color:#1e2022;pointer-events:none}
@ -201,13 +202,13 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_block_selection,.webix_cell,.webix_hcell,.webix_ss_footer td,.webix_ss_header td,.webix_table_cell,.webix_view.webix_table_cell{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_block_selection{position:absolute}
.webix_ss_sort_asc,.webix_ss_sort_desc{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}
.webix_hcell.webix_ss_filter{padding:2px 5px}
.webix_hcell.webix_ss_filter{padding:2px 5px 2px 5px}
.webix_ss_filter input,.webix_ss_filter select{width:100%;font-size:inherit;color:#1e2022!important;height:30px;margin-top:-2px;padding:0 3px;vertical-align:top;border:1px solid #a4bed4;line-height:30px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:Helvetica,Verdana}
.webix_richfilter{margin-top:1px;line-height:30px}
.webix_ss_filter select{padding:3px}
.webix_dd_drag_column,.webix_ss_header,.webix_ss_header TD,.webix_ss_vscroll_header{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%)}
.webix_dd_drag_column,.webix_ss_header,.webix_ss_header TD,.webix_ss_vscroll_header{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x}
.webix_ss_footer TD,.webix_ss_vscroll_footer{background:#fafafa}
.webix_hcell{padding:0 10px;text-align:left}
.webix_hcell{padding:0 10px 0 10px;text-align:left}
.webix_ss_header td{border-right:1px solid #a4bed4;border-bottom:1px solid #a4bed4}
.webix_ss_footer td{border-right:1px solid #ebebeb;border-top:1px solid #ebebeb}
.webix_size_row td{border:none}
@ -222,31 +223,32 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_block_selection{background:rgba(0,0,0,.1);border:2px solid #ffd47b}
.webix_dd_drag{white-space:nowrap;overflow:hidden;border-left:1px solid #ebebeb;height:34px}
.webix_dd_drag>div{display:inline-block;vertical-align:top;background:#fff;border-top:1px solid #ebebeb;border-right:1px solid #ebebeb;border-bottom:1px solid #ebebeb;padding:5px 10px;height:34px;line-height:26px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_dd_drag_column{padding:5px 10px}
.webix_dd_drag_column{padding:5px 10px 5px 10px}
.webix_column>.webix_drag_over.webix_cell{background-color:#e6e6e6;color:#1e2022}
.webix_ss_header table,.webix_ss_header td{padding:0;margin:0}
.webix_cell.webix_invalid,.webix_column>.webix_cell.webix_invalid:nth-child(even){background-color:#fee}
.webix_invalid_cell{position:relative}
.webix_invalid_cell:after{content:"";position:absolute;top:0;right:0;width:0;height:1px;border-top:8px solid #f44;border-left:8px solid transparent}
.webix_column>div.webix_cell_select,.webix_column>div.webix_column_select,.webix_column>div.webix_row_select{color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background:-webkit-linear-gradient(#ffebc2,#ffdb8f);background:-moz-linear-gradient(#ffebc2,#ffdb8f);background:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_column>div.webix_cell_select,.webix_column>div.webix_column_select,.webix_column>div.webix_row_select{background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_column>div.webix_cell_select{border-bottom:1px solid #ffd47b;box-shadow:0 1px #ffe3a9 inset;border-right:1px solid #ffd47b;border-left:1px solid #ffd47b;padding-top:0;padding-left:9px}
.webix_ss_right .webix_column.webix_first>div.webix_cell_select{padding-left:10px}
.webix_column>div.webix_invalid.webix_row_select:nth-child(even),.webix_column>div.webix_row_select{border-bottom:1px solid #ffd47b;box-shadow:0 1px #ffe3a9 inset;padding-top:0}
.webix_column>div.webix_column_select{border-right:1px solid #ffd47b;border-left:1px solid #ffd47b;padding-left:9px}
.webix_column>.webix_cell.webix_invalid.webix_cell_select:nth-child(even){color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background:-webkit-linear-gradient(#ffebc2,#ffdb8f);background:-moz-linear-gradient(#ffebc2,#ffdb8f);background:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_cell.webix_dtable_colrow,.webix_cell.webix_dtable_subrow,.webix_cell.webix_dtable_subview{position:absolute;left:0;top:0;background-color:#fff;width:100%;padding-right:28px;padding-left:10px;padding-top:1px;border-bottom:1px solid #ebebeb}
.webix_column>.webix_cell.webix_invalid.webix_cell_select:nth-child(even){background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_cell.webix_dtable_colrow,.webix_cell.webix_dtable_subrow,.webix_dtable_subview{position:absolute;left:0;top:0;background-color:#fff;width:100%;padding-right:28px;padding-left:10px;padding-top:1px;border-bottom:1px solid #ebebeb}
.webix_cell.webix_dtable_colrow.webix_selected{background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_dtable_subrow{border-top:1px solid #ebebeb;text-align:right}
.webix_dtable_subview{background:#ebebeb;border-top:1px solid #ebebeb;padding:0 0 0 10px;box-sizing:border-box}
.webix_dtable_subview{background:#ebebeb;border-top:1px solid #ebebeb;padding:0;padding-left:10px;box-sizing:border-box}
.number .webix_cell{text-align:right}
.webix_rotate{transform:rotate(-90deg);-webkit-transform:rotate(-90deg);line-height:normal}
.webix_measure_rotate{line-height:normal;white-space:normal;padding:10px}
.webix_span_layer,.webix_span_layer_top{background:0 0;position:absolute;left:0;top:0;height:0;width:0;overflow:visible}
.webix_span_layer_top{z-index:1;overflow:hidden}
.webix_span_layer_top{z-index:1}
.webix_ss_right .webix_span_layer,.webix_ss_right .webix_span_layer_top{border-left:1px solid #a4bed4}
.webix_dtable_span{position:absolute;background:#fff;text-align:left}
.webix_dtable_span.webix_selected{color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background:-webkit-linear-gradient(#ffebc2,#ffdb8f);background:-moz-linear-gradient(#ffebc2,#ffdb8f);background:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_dtable_span.webix_selected{background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_hcell span.webix_input_icon{background-color:#a4bed4}
.webix_area_selection_layer{position:absolute;z-index:1}
.webix_area_selection_layer{position:absolute;z-index:2}
.webix_area_selection{position:absolute;background:#1e2022}
.webix_area_selection_bottom,.webix_area_selection_top{height:2px}
.webix_area_selection_left,.webix_area_selection_right{width:2px}
@ -256,7 +258,7 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_win_body{overflow:hidden}
.webix_win_body,.webix_win_body>.webix_view,.webix_win_body>.webix_view .webix_cal_month,.webix_win_content,.webix_window{border-radius:0}
.webix_win_head{border-bottom:1px solid silver}
.webix_win_head>.webix_view>.webix_template{font-family:Helvetica,Verdana;font-size:13px;font-weight:700;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);padding:0;text-align:center;line-height:34px}
.webix_win_head>.webix_view>.webix_template{font-family:Helvetica,Verdana;color:#1e2022;font-size:13px;font-weight:700;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x;padding:0;text-align:center;line-height:34px}
.webix_win_head>.webix_view>.webix_template .webix_el_label,.webix_win_head>.webix_view>.webix_template .webix_inp_label{color:#1e2022}
.webix_win_content{height:auto;width:auto;overflow:hidden}
.webix_modal{width:100%;height:100%;position:fixed;top:0;left:0;background-color:#000;filter:alpha(opacity=20);opacity:.2}
@ -268,18 +270,19 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_point_bottom{background-position:0 0}
.webix_point_right{background-position:0 -22px}
.webix_point_left{background-position:0 -9px}
.webix_resize_handle{position:absolute;width:15px;height:15px;bottom:0;line-height:15px;right:-1px;text-align:center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAAABlBMVEUAAAAAAAClZ7nPAAAAAXRSTlMAQObYZgAAABZJREFUeAFjIAUwUshlpJDLSIhLGAAACQ4AFk79JaMAAAAASUVORK5CYII=);cursor:nw-resize}
.webix_resize_handle{position:absolute;z-index:2;width:15px;height:15px;bottom:0;line-height:15px;right:-1px;text-align:center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAAABlBMVEUAAAAAAAClZ7nPAAAAAXRSTlMAQObYZgAAABZJREFUeAFjIAUwUshlpJDLSIhLGAAACQ4AFk79JaMAAAAASUVORK5CYII=);cursor:nw-resize}
.webix_resize_frame{position:absolute;filter:alpha(opacity=10);opacity:.1;background:#d6e8ff;display:block;border:1px solid #70afff;box-shadow:1px 3px 6px #000}
.webix_resize_cursor{cursor:nw-resize}
.webix_tree .webix_scroll_cont>.webix_tree_leaves{padding:9px 10px 9px 9px}
.webix_tree_item{clear:both;height:22px;line-height:22px;white-space:nowrap}
.webix_tree_item.webix_selected{background:0 0}
.webix_tree_item.webix_selected span{padding:4px 10px 4px 4px;margin-left:-4px;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background:-webkit-linear-gradient(#ffebc2,#ffdb8f);background:-moz-linear-gradient(#ffebc2,#ffdb8f);background:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_tree_item.webix_selected span{padding:4px 10px 4px 4px;margin-left:-4px;background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_tree_item.webix_invalid{background-color:#fee}
.webix_tree_checkbox{margin:1px 0 0;padding:0;float:left;vertical-align:middle;height:100%;width:13px}
.webix_indeterminate{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gcCCSwfRyGesAAAAAxpVFh0Q29tbWVudAAAAAAAvK6ymQAAAExJREFUKM9jLCgo+M9AAmBhYGBgaGtrY+Tk5MSrsLCwkIGBgeE/EwOJgGQNLMgcJSUlBgYGBnQ/Md67d498G+jsB6hbGQfWSYykJg0AUMsPVoNrFX0AAAAASUVORK5CYII=);background-repeat:no-repeat;background-position:left center;height:100%;width:13px;margin-top:0!important}
.webix_measure_size input,.webix_measure_size select,.webix_measure_size textarea{width:5px}
.webix_measure_size div{margin-left:-5px;float:none}
.webix_measure_size a,.webix_measure_size div{display:inline-block!important}
.webix_measure_size a,.webix_measure_size div{display:inline-block!important;position:static!important}
.webix_tree_close,.webix_tree_file,.webix_tree_folder,.webix_tree_folder_open,.webix_tree_none,.webix_tree_open{float:left;width:20px;height:100%;cursor:pointer;margin:0;background-repeat:no-repeat}
.webix_tree_close,.webix_tree_none,.webix_tree_open{background-position:center center}
.webix_cell .webix_tree_close,.webix_cell .webix_tree_none,.webix_cell .webix_tree_open{background-color:transparent}
@ -291,7 +294,7 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_tree_file{background-image:url(data:image/gif;base64,R0lGODlhEgASAMQVAPv7+2RkZPf39/r6+vj4+Pn5+fT09Pb29vX19fHx8fDw8Onp6fLy8u7u7uzs7PPz8+vr6+rq6uXl5ejo6O/v7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABUALAAAAAASABIAAAV4YCWOZGkGaKqaVSAMQCwLQnAOj6ErzUTXpQDgQDgcGJTFDzgSEp4HRCKytDUBMKzAoIAsJACrSCjTGhINR5hELg8ECEZifS3HCgQEgj62xwZPAnwtbgMDBQU0g21Yh4iIi3aGkzBihH52lgEEmDIEli0qoigspSYhADs=)}
.webix_tree_folder{background-image:url(data:image/gif;base64,R0lGODlhEgASAMQfAPvjpP/24fPHVvnUdvzotdSiKv/23vvrw/LCS/C+RfnelvPMaf/88/nbi/rsyerYq/TLYv7y1v7wzeCsLO+8P86dJfvv0MuaIsydKPPOc+SqGKGEPe/AS+zVneWwLf///yH5BAEAAB8ALAAAAAASABIAAAWZ4CdeZGleYvpdA+O+zNUBqHoZOB4EceHUqVtuF+n9VCtdQCI5BC6FA3BkCEQkBALAACVMV9eDVhGJQGnIixigaAwiG6jie2G7BxDLpVJozG13EAICPxUeGRleQQMLgggJUhiHC3pBggKPFJETGZRAF5gJCRSaFxgTC55BCByioz+nEKojGgmtHBwPJAUCELo2J8FfSMTFxsUhADs=)}
.webix_tree_folder_open{background-image:url(data:image/gif;base64,R0lGODlhEgASAMQfAPXMWPK9N/fipOzLbPrVaP/89frqwv3tuvvprfLES+7PdP7xyP7z0vPAQfvtyMuaIv/32/735OSqFv3de+7ReP7lmf7gh/nv0v/67unFXfb29vK/PenFSaGEPfLnyv///yH5BAEAAB8ALAAAAAASABIAAAWS4Cc+ZGk+YvqZRVtgGiag6sNBThlFWnTQqQcE4sqRFj/VashsYR6HZI0JWSAjDwQCOGIgERULg/EQzJRQsGVCYHTK51qYTQDkFPj4iA4AJHIUgQoGQA8EdX4NhHgKAxeFfQkJGwGLeI6Fkg2UlQ8Dn5hBCZuchKChIxKkGw05Ga8DHlwkqg2tJ1xBtDlKvTUkviEAOw==)}
.webix_tree_img{background:0 0;float:left;width:18px;height:22px}
.webix_tree_img{background:0 0;float:left;width:18px;height:22px;background-position:0 0}
.webix_tree_plus2{background-image:url(data:image/gif;base64,R0lGODlhEgASAMQfAFSWrmi52FCPplORqVmet8HBwfn//02KoE+NpEyIn2a21E2Jn2u/3mzB4Vqguk6LomGtyWGuy27E5VqivG/H51OUrE+OpVyhu1eXr2CqxV6lwFaas06LoXHJ6lKTqgAAACH5BAEAAB8ALAAAAAASABIAAAVZ4CeOYkGeaJmuKpuaLgrHX7IcD2IJrs0hAk8FAGAlDoiBYUNwTIyPAcagyUAirAXCwOUGAoVwmHSwVAiGSIDRYB0EgIthLaG44RN1g9JxwR0QdDSDhIWGKyEAOw==);background-repeat:no-repeat}
.webix_tree_plus3{background-image:url(data:image/gif;base64,R0lGODlhEgASAMQfAFSWrmi52FCPplORqVmet8HBwfn//02KoE+NpEyIn2a21E2Jn2u/3mzB4Vqguk6LomGtyWGuy27E5VqivG/H51OUrE+OpVyhu1eXr2CqxV6lwFaas06LoXHJ6lKTqgAAACH5BAEAAB8ALAAAAAASABIAAAVb4CeOYkGeaJmuKpuaLgrHX7IcD2IJrs0hAk8FAGAlDoiBYUNwTIyPAcagyUAirAXCwOUGAoVwmHSwVAiGSIDRYB0EgIthLaG44RN1g9JxwR0QdDQtg4SFM4csIQA7)}
.webix_tree_plus4{background-image:url(data:image/gif;base64,R0lGODlhEgASAMQfAFSWrmi52FCPplORqVmet/n//8HBwU2KoE+NpEyIn2a21E2Jn2u/3mzB4VqgumGtyWGuy27E5VqivE6Lom/H51OUrE+OpVyhu1eXr2CqxV6lwFaas06LoVKTqnHJ6gAAACH5BAEAAB8ALAAAAAASABIAAAVY4CeOZGmeaKqubEsmyzEhlqDCHCJ0FQCkiQNiUNgQHBLgZIApaDIPSGqBKFitgYBhuyUdLBVCARJgNFIHAeBSKEcoaLWE3KB4VGrHw+0yuEZ+fx+Bf4QmIQA7)}
@ -308,9 +311,9 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_cal_next_button,.webix_cal_prev_button{cursor:pointer;position:absolute;top:17px;width:30px;height:28px;background-position:11.5px 4px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}
.webix_cal_prev_button{left:17px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAALCAYAAACzkJeoAAAASUlEQVR42p2QMQoAQQgD79EZ0Mqn5xCu2cPdYgUbJ0rMMxXgLeiuKq8gsJAz8weQ0QiwJEfECnr4wdlEnwJ68+yyhReC+c85oRecj0Um+pmo9wAAAABJRU5ErkJggg==);background-repeat:no-repeat}
.webix_cal_next_button{right:17px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAALCAYAAACzkJeoAAAARElEQVR42qXPsQoAIAhF0T76PdDJT7cUmtQhcmk4N8QVQ9JXN2bmgWOgqp+BiCRG2AYAMoi3/LxYdyagAnhA6G93TrABZaJFJjrFY8IAAAAASUVORK5CYII=);background-repeat:no-repeat}
.webix_view>.webix_cal_header{margin:0 17px 10px;height:auto}
.webix_view>.webix_cal_header{margin:0 17px 10px 17px;height:auto}
.webix_view>.webix_cal_header div{float:left;text-align:center;height:19px;font-size:11px;color:#1e2022;border-bottom:#cecece 1px solid;margin-bottom:7px}
.webix_cal_body{margin:0 17px}
.webix_cal_body{margin:0 17px 0 17px}
.webix_cal_body .webix_cal_row{clear:both}
.webix_cal_body .webix_cal_row>div{float:left;text-align:center;height:100%}
.webix_cal_body .webix_cal_select,.webix_cal_body .webix_cal_select.webix_cal_today,.webix_cal_body .webix_selected{color:#1e2022;background:#ffdb8f}
@ -325,30 +328,30 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_cal_block{float:left;text-align:center;cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}
.webix_selected{background:#ffdb8f;color:#1e2022}
.webix_cal_footer{text-align:center;font-size:12px;color:#444;margin:4px 17px;padding-top:2px;cursor:pointer}
.webix_cal_icons{float:right;padding:4px}
.webix_cal_icons{float:right;padding:4px 4px}
.webix_cal_time{padding:2px 4px}
.webix_cal_time_icons{float:left}
.webix_cal_icons .webix_cal_icon{text-align:center;padding:2px 4px}
.webix_cal_icon:hover,.webix_cal_month_name:hover,.webix_cal_time:hover{text-decoration:underline;color:#d6e8ff}
.webix_cal_month_name.webix_readonly:hover{text-decoration:none;color:#1e2022;cursor:default}
.webix_time_header{padding:17px 17px 1px}
.webix_time_header{padding:17px 17px 1px 17px}
.webix_time_header .webix_cal_hours,.webix_time_header .webix_cal_minutes{display:inline-block;font-size:14px;text-align:center;height:26px;line-height:22px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #a4bed4}
.webix_time_header .webix_cal_minutes{padding-left:1px;border-left:none}
.webix_time_header .webix_cal_hours{border-right:none!important}
.webix_cal_body .webix_hours{float:left;border-right:1px solid #cecece;padding-right:1px}
.webix_cal_body .webix_minutes{float:left;padding-left:1px}
.webix_cal_block_empty{float:left;text-align:center}
.webix_time_footer{text-align:center;font-size:12px;padding:7px 17px 0;cursor:pointer}
.webix_cal_done{margin-top:3px;padding:2px 7px;font-size:12px;border-radius:6px;border:1px solid #a4bed4;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);float:right}
.webix_time_footer{text-align:center;font-size:12px;padding:7px 17px 0 17px;cursor:pointer}
.webix_cal_done{margin-top:3px;padding:2px 7px;font-size:12px;border-radius:6px;border:1px solid #a4bed4;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x;float:right}
.webix_cal_blurred_hours{background-color:#f7f7f7}
.webix_property_line{clear:both;width:100%;min-height:24px;height:auto}
.webix_property_line:nth-child(odd){background-color:#f7f7f7}
.webix_property_label,.webix_property_value{height:24px;line-height:24px;padding-left:10px;float:left;border-bottom:1px solid #a4bed4;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden}
.webix_property_label{border-right:1px solid #a4bed4}
.webix_property_label_line{padding-left:10px;font-family:Helvetica,Verdana;font-size:13px;font-weight:700;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);line-height:32px;line-height:23px;border-bottom:1px solid #ebebeb}
.webix_property_label_line{padding-left:10px;font-family:Helvetica,Verdana;color:#1e2022;font-size:13px;font-weight:700;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x;line-height:32px;line-height:23px;border-bottom:1px solid #ebebeb}
.webix_property_label_line .webix_el_label,.webix_property_label_line .webix_inp_label{color:#1e2022}
.webix_property_col_val{width:100%;height:100%;-moz-user-select:text;-webkit-user-select:text;user-select:text}
.webix_property_col_ind{float:right;border:1px solid #a4bed4;border-radius:2px;width:30px;cursor:pointer;height:13px;margin:3px 10px 3px 0}
.webix_property_col_ind{float:right;border:1px solid #a4bed4;border-radius:3px;width:16px;cursor:pointer;height:16px;margin:4px 10px 3px 0}
.webix_property_value{text-overflow:ellipsis;white-space:nowrap}
.webix_property_check{margin-top:5px}
.webix_tooltip{display:none;position:absolute;z-index:10000;background-color:#fff;padding:5px 10px;border:1px solid #a4bed4;font-family:Helvetica,Verdana;font-size:13px;color:#1e2022;border-radius:0;box-shadow:1px 1px 0 0 #CCC}
@ -377,16 +380,16 @@ div.webix_modal_cover{background-color:#000;cursor:default;filter:alpha(opacity=
.webix_el_button button,.webix_el_button input,.webix_el_toggle button,.webix_el_toggle input,.webixbutton{border-radius:6px;border:1px solid #a4bed4;height:100%;width:100%;cursor:pointer;font-size:13px;font-family:Helvetica,Verdana;-webkit-appearance:none}
.webix_el_button .webix_img_btn,.webix_el_button .webix_img_btn .webix_img_btn_text,.webix_el_button .webix_img_btn_top,.webix_el_button .webix_img_btn_top .webix_img_btn_text,.webix_el_toggle .webix_img_btn,.webix_el_toggle .webix_img_btn .webix_img_btn_text,.webix_el_toggle .webix_img_btn_top,.webix_el_toggle .webix_img_btn_top .webix_img_btn_text{color:#1e2022}
.webix_el_button .webix_img_btn,.webix_el_button .webix_img_btn_top,.webix_el_toggle .webix_img_btn,.webix_el_toggle .webix_img_btn_top{border:0}
.webixbutton,.webixtype_base,.webixtype_next,.webixtype_prev{color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background:-webkit-linear-gradient(#fff,#e6e6e6);background:-moz-linear-gradient(#fff,#e6e6e6);background:-ms-linear-gradient(top,#fff,#e6e6e6);background:-o-linear-gradient(top,#fff,#e6e6e6);font-size:13px;font-family:Helvetica,Verdana;padding:0;border:0}
.webixtype_form{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%)}
.webixtype_form:active{box-shadow:inset 0 3px 5px rgba(0,0,0,.125);background:no-repeat #d6e8ff}
.webix_el_button .webixtype_danger{background:#c10;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#e7877e),color-stop(100%,#c10));background:-webkit-linear-gradient(#e7877e,#c10);background:-moz-linear-gradient(#e7877e,#c10);background:-ms-linear-gradient(top,#e7877e,#c10);background:-o-linear-gradient(top,#e7877e,#c10);border:none!important;color:#fff}
.webixbutton,.webixtype_base,.webixtype_next,.webixtype_prev{color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background-image:-webkit-linear-gradient(#fff,#e6e6e6);background-image:-moz-linear-gradient(#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);font-size:13px;font-family:Helvetica,Verdana;padding:0;border:0}
.webixtype_form{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x}
.webixtype_form:active{box-shadow:inset 0 3px 5px rgba(0,0,0,.125);background:#d6e8ff;background-repeat:no-repeat}
.webix_el_button .webixtype_danger{background:#c10;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#e7877e),color-stop(100%,#c10));background-image:-webkit-linear-gradient(#e7877e,#c10);background-image:-moz-linear-gradient(#e7877e,#c10);background-image:-ms-linear-gradient(top,#e7877e,#c10);background-image:-o-linear-gradient(top,#e7877e,#c10);border:none!important;color:#fff}
.webix_el_button .webix_el_box,.webix_el_toggle .webix_el_box{position:relative}
.webix_el_button .webix_el_arrow,.webix_el_toggle .webix_el_arrow{position:absolute;z-index:1}
.webixtype_next,.webixtype_prev{position:absolute;z-index:2;top:0}
input.webixtype_prev{border-left-width:0;border-radius:0 6px 6px 0;-webkit-border-radius:0 6px 6px 0;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}
input.webixtype_next{border-right-width:0;border-radius:6px 0 0 6px;-webkit-border-radius:6px 0 0 6px;-moz-border-radius-topleft:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0}
.webix_el_arrow{width:18px;height:18px;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background:-webkit-linear-gradient(#fff,#e6e6e6);background:-moz-linear-gradient(#fff,#e6e6e6);background:-ms-linear-gradient(top,#fff,#e6e6e6);background:-o-linear-gradient(top,#fff,#e6e6e6);border:1px solid #a4bed4}
.webix_el_button .webix_el_arrow,.webix_el_toggle .webix_el_arrow{position:absolute}
.webixtype_next,.webixtype_prev{position:absolute;z-index:1;top:0}
input.webixtype_prev{border-left-width:0;border-radius:0;-webkit-border-top-left-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:6px;border-bottom-right-radius:6px}
input.webixtype_next{border-right-width:0;border-radius:0;-webkit-border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-moz-border-radius-topleft:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-top-left-radius:6px;border-bottom-left-radius:6px;border-top-right-radius:0;border-bottom-right-radius:0}
.webix_el_arrow{width:18px;height:18px;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background-image:-webkit-linear-gradient(#fff,#e6e6e6);background-image:-moz-linear-gradient(#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);border:1px solid #a4bed4}
.webixtype_prev_arrow{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg)}
.webixtype_next_arrow{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg)}
.webix_img_btn_abs_top .webix_icon,.webix_img_btn_top .webix_icon{font-size:22px;position:absolute;top:8px;left:50%}
@ -405,7 +408,7 @@ input.webixtype_next{border-right-width:0;border-radius:6px 0 0 6px;-webkit-bord
.webix_img_btn_top{background-position:center top;vertical-align:top}
.webix_img_btn_abs .webix_img_btn_text{bottom:8px}
.webix_pressed .webix_img_btn,.webix_pressed .webix_img_btn_top{box-shadow:inset 0 3px 5px rgba(0,0,0,.125);background-color:rgba(0,0,0,.05)}
.webix_control .webix_disabled_box .webix_el_arrow,.webix_control .webix_disabled_box .webix_img_btn,.webix_control .webix_disabled_box .webixtype_base,.webix_control .webix_disabled_box .webixtype_danger,.webix_control .webix_disabled_box .webixtype_form,.webix_control .webix_disabled_box .webixtype_next,.webix_control .webix_disabled_box .webixtype_prev{color:#aaa!important;background:#e9e9e9;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fbfbfb),color-stop(100%,#e9e9e9));background:-webkit-linear-gradient(#fbfbfb,#e9e9e9);background:-moz-linear-gradient(#fbfbfb,#e9e9e9);background:-ms-linear-gradient(top,#fbfbfb,#e9e9e9);background:-o-linear-gradient(top,#fbfbfb,#e9e9e9);border-color:#d5d5d5!important}
.webix_control .webix_disabled_box .webix_el_arrow,.webix_control .webix_disabled_box .webix_img_btn,.webix_control .webix_disabled_box .webixtype_base,.webix_control .webix_disabled_box .webixtype_danger,.webix_control .webix_disabled_box .webixtype_form,.webix_control .webix_disabled_box .webixtype_next,.webix_control .webix_disabled_box .webixtype_prev{color:#aaa!important;background:#e9e9e9;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fbfbfb),color-stop(100%,#e9e9e9));background-image:-webkit-linear-gradient(#fbfbfb,#e9e9e9);background-image:-moz-linear-gradient(#fbfbfb,#e9e9e9);background-image:-ms-linear-gradient(top,#fbfbfb,#e9e9e9);background-image:-o-linear-gradient(top,#fbfbfb,#e9e9e9);border-color:#d5d5d5!important}
.webix_control .webix_disabled_box .webix_img_btn_text{color:#aaa}
.webix_control .webix_disabled_box .webix_image{opacity:.4}
.webix_disabled_view.webix_control .webix_icon,.webix_disabled_view.webix_control .webix_icon_btn,.webix_layout_toolbar.webix_toolbar .webix_disabled_view.webix_control .webix_disabled_box .webix_img_btn_text,.webix_layout_toolbar.webix_toolbar .webix_disabled_view.webix_control .webix_icon,.webix_layout_toolbar.webix_toolbar .webix_disabled_view.webix_control .webix_icon_btn{color:#aaa}
@ -415,31 +418,31 @@ input.webixtype_next{border-right-width:0;border-radius:6px 0 0 6px;-webkit-bord
.webix_richtext_container .webix_template{padding:10px;overflow-x:auto;border:solid #ccc;border-width:0 1px 1px;border-radius:0 0 6px 6px}
.webix_control{background:0 0}
.webix_control button,.webix_control input,.webix_control textarea,.webix_el_label,.webix_inp_bottom_label,.webix_inp_label,.webix_inp_top_label{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:Helvetica,Verdana}
.webix_el_box{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:2px;height:100%;width:100%;font-size:13px;overflow:hidden}
.webix_el_box{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:2px 2px;height:100%;width:100%;font-size:13px;overflow:hidden}
.webix_el_colorpicker input,.webix_el_combo input,.webix_el_datepicker input,.webix_el_search input,.webix_el_text input{height:100%;padding:0 10px;border:1px solid #a4bed4;color:#1e2022;font-size:13px;font-family:Helvetica,Verdana;-webkit-appearance:none;border-radius:0}
.webix_inp_label,.webix_inp_top_label,.webix_label_right{color:#1e2022;text-transform:none;font-size:13px}
.webix_inp_label{float:left;padding-top:1px;padding-left:2px;padding-right:7.5px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}
.webix_inp_top_label{float:none;padding:2px 2px 0}
.webix_inp_top_label{float:none;padding:2px 2px;padding-bottom:0}
.webix_inp_bottom_label{font-size:11px;color:#2a2d30}
.webix_label_right{padding-left:7.5px}
.webix_el_checkbox .webix_label_right{display:inline-block;padding-top:2px}
.webix_el_label{color:#1e2022;line-height:30px;padding:2px}
.webix_el_label{color:#1e2022;line-height:30px;padding:2px 2px}
.webix_toolbar .webix_el_label{padding-left:10px;text-transform:none}
.webix_el_select select{height:100%;font-size:13px;font-family:Helvetica,Verdana;border:1px solid #a4bed4}
body:not(:-moz-handler-blocked) .webix_el_select select{padding:.2em}
.webix_all_segments,.webix_el_group{height:100%;white-space:nowrap}
.webix_inp_counter_next,.webix_inp_counter_prev,.webix_inp_counter_value{border:1px solid #a4bed4;cursor:pointer;-webkit-appearance:none;width:20px;height:100%;vertical-align:top}
.webix_inp_counter_value{font-size:13px;width:50px;color:#1e2022;text-align:center;border-left-width:0;border-right-width:0;-webkit-appearance:none;border-radius:0}
.webix_inp_counter_prev{padding-left:6px;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background:-webkit-linear-gradient(#fff,#e6e6e6);background:-moz-linear-gradient(#fff,#e6e6e6);background:-ms-linear-gradient(top,#fff,#e6e6e6);background:-o-linear-gradient(top,#fff,#e6e6e6);-webkit-border-radius:6px 0 0 6px;-moz-border-radius-topleft:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-radius:6px 0 0 6px}
.webix_inp_counter_next{padding-left:6px;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background:-webkit-linear-gradient(#fff,#e6e6e6);background:-moz-linear-gradient(#fff,#e6e6e6);background:-ms-linear-gradient(top,#fff,#e6e6e6);background:-o-linear-gradient(top,#fff,#e6e6e6);-webkit-border-radius:0 6px 6px 0;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px;border-radius:0 6px 6px 0}
.webix_el_textarea textarea{border:1px solid #a4bed4;height:100%;margin:0;padding:5px 10px;color:#1e2022;resize:none;font-size:13px;font-family:Helvetica,Verdana}
.webix_inp_counter_prev{padding-left:6px;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background-image:-webkit-linear-gradient(#fff,#e6e6e6);background-image:-moz-linear-gradient(#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);-webkit-border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-moz-border-radius-topleft:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-top-left-radius:6px;border-bottom-left-radius:6px;border-top-right-radius:0;border-bottom-right-radius:0}
.webix_inp_counter_next{padding-left:6px;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background-image:-webkit-linear-gradient(#fff,#e6e6e6);background-image:-moz-linear-gradient(#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);-webkit-border-top-left-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:6px;border-bottom-right-radius:6px}
.webix_el_textarea textarea{border:1px solid #a4bed4;height:100%;margin:0;padding:5px;color:#1e2022;resize:none;font-size:13px;font-family:Helvetica,Verdana;padding-left:10px;padding-right:10px}
.webix_el_textarea .webix_inp_label{padding-top:8.5px}
.webix_segment_0,.webix_segment_1{border:1px solid #a4bed4;border-right-width:0;height:100%}
.webix_segment_0{-webkit-border-radius:6px 0 0 6px;-moz-border-radius-topleft:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-radius:6px 0 0 6px}
.webix_segment_N{border:1px solid #a4bed4;height:100%;-webkit-border-radius:0 6px 6px 0;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px;border-radius:0 6px 6px 0}
.webix_segment_N:first-child{-webkit-border-radius:6px;-moz-border-radius-topleft:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px;border-radius:6px}
.webix_segment_0,.webix_segment_1,.webix_segment_N{-webkit-appearance:none;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background:-webkit-linear-gradient(#fff,#e6e6e6);background:-moz-linear-gradient(#fff,#e6e6e6);background:-ms-linear-gradient(top,#fff,#e6e6e6);background:-o-linear-gradient(top,#fff,#e6e6e6);font-size:13px;font-family:Helvetica,Verdana;cursor:pointer;padding:0}
.webix_segment_0.webix_selected,.webix_segment_1.webix_selected,.webix_segment_N.webix_selected{color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background:-webkit-linear-gradient(#ffebc2,#ffdb8f);background:-moz-linear-gradient(#ffebc2,#ffdb8f);background:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_segment_0{-webkit-border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-moz-border-radius-topleft:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-top-left-radius:6px;border-bottom-left-radius:6px;border-top-right-radius:0;border-bottom-right-radius:0}
.webix_segment_N{border:1px solid #a4bed4;height:100%;-webkit-border-top-left-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:6px;border-bottom-right-radius:6px}
.webix_segment_N:first-child{-webkit-border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-webkit-border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-topleft:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px;border-top-left-radius:6px;border-bottom-left-radius:6px;border-top-right-radius:6px;border-bottom-right-radius:6px}
.webix_segment_0,.webix_segment_1,.webix_segment_N{-webkit-appearance:none;color:#1e2022;background:#e6e6e6;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e6e6e6));background-image:-webkit-linear-gradient(#fff,#e6e6e6);background-image:-moz-linear-gradient(#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);font-size:13px;font-family:Helvetica,Verdana;cursor:pointer;padding:0}
.webix_segment_0.webix_selected,.webix_segment_1.webix_selected,.webix_segment_N.webix_selected{background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_inp_static{border:1px solid #a4bed4;background:#fff;overflow:hidden;padding:0 10px;height:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;float:left}
.webix_inp_static .webix_placeholder{color:#666d73}
.webix_el_colorpicker,.webix_el_combo,.webix_el_datepicker,.webix_el_richselect,.webix_el_search{font-size:13px}
@ -465,15 +468,15 @@ body:not(:-moz-handler-blocked) .webix_el_select select{padding:.2em}
.webix_disabled_view.webix_control .webix_image{-webkit-filter:grayscale(100%);filter:grayscale(100%)}
.webix_view.webix_control .webix_disabled_box .webix_input_icon,.webix_view.webix_control .webix_disabled_box button,.webix_view.webix_control .webix_disabled_box label{color:#aaa}
.webix_view.webix_control .webix_disabled_box .webix_inp_static,.webix_view.webix_control .webix_disabled_box input,.webix_view.webix_control .webix_disabled_box select,.webix_view.webix_control .webix_disabled_box textarea{color:#aaa;background:#eee}
.webix_view.webix_control .webix_disabled_box .webix_inp_counter_next,.webix_view.webix_control .webix_disabled_box .webix_inp_counter_prev,.webix_view.webix_control .webix_disabled_box .webix_segment_0,.webix_view.webix_control .webix_disabled_box .webix_segment_1,.webix_view.webix_control .webix_disabled_box .webix_segment_N{color:#aaa!important;background:#e9e9e9;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fbfbfb),color-stop(100%,#e9e9e9));background:-webkit-linear-gradient(#fbfbfb,#e9e9e9);background:-moz-linear-gradient(#fbfbfb,#e9e9e9);background:-ms-linear-gradient(top,#fbfbfb,#e9e9e9);background:-o-linear-gradient(top,#fbfbfb,#e9e9e9);border-color:#d5d5d5!important}
.webix_view.webix_control .webix_disabled_box .webix_inp_counter_next,.webix_view.webix_control .webix_disabled_box .webix_inp_counter_prev,.webix_view.webix_control .webix_disabled_box .webix_segment_0,.webix_view.webix_control .webix_disabled_box .webix_segment_1,.webix_view.webix_control .webix_disabled_box .webix_segment_N{color:#aaa!important;background:#e9e9e9;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fbfbfb),color-stop(100%,#e9e9e9));background-image:-webkit-linear-gradient(#fbfbfb,#e9e9e9);background-image:-moz-linear-gradient(#fbfbfb,#e9e9e9);background-image:-ms-linear-gradient(top,#fbfbfb,#e9e9e9);background-image:-o-linear-gradient(top,#fbfbfb,#e9e9e9);border-color:#d5d5d5!important}
.webix_disabled_top_label{color:#aaa}
label.webix_required:after{padding-left:4px;content:"*";color:red}
label.webix_required:after,legend.webix_required:after{padding-left:4px;content:"*";color:red}
.webix_multicombo .webix_inp_static{padding:0 3px}
.webix_el_text .webix_multicombo_input{background-color:transparent;border:0;float:left;vertical-align:middle;padding:0;color:#1e2022;font-size:13px;font-family:Helvetica,Verdana;margin-left:7px}
.webix_el_text .webix_multicombo_input:focus{border:0;box-shadow:none}
.webix_multicombo_listbox{width:auto;line-height:1;margin:0;padding:0;list-style:none}
.webix_multicombo_tag,.webix_multicombo_value{padding:0 5px 0 7px;background-color:#f2f2f2;display:inline-block;margin:3px;float:left;border-radius:6px}
.webix_multicombo_tag{min-width:15px;text-align:center;padding:0 5px}
.webix_multicombo_tag{min-width:15px;text-align:center;padding:0 5px 0 5px}
.webix_multicombo_delete{margin-left:10px;padding:0 5px;color:#000;cursor:pointer}
.webix_multilist .webix_selected{background:#f2f2f2;color:#1e2022}
.webix_checksuggest_select_all{border:none;border-bottom:1px solid #ebebeb;border-color:#ebebeb;margin-bottom:1px}
@ -485,13 +488,13 @@ label.webix_required:after{padding-left:4px;content:"*";color:red}
.webix_tab_filler{display:table-cell;background:0 0;font-size:1px;border-bottom:1px solid #a4bed4;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_tab_filler:first-child{border-right:1px solid #a4bed4}
.webix_item_tab:first-child{border-left:1px solid #a4bed4}
.webix_item_tab{display:table-cell;text-align:center;vertical-align:middle;overflow:hidden;cursor:pointer;border:1px solid #a4bed4;border-left-width:0;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);-webkit-border-radius:0;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-radius:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_item_tab{display:table-cell;text-align:center;vertical-align:middle;overflow:hidden;cursor:pointer;border:1px solid #a4bed4;border-left-width:0;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x;-webkit-border-top-left-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webixtype_bottom .webix_item_tab{border-radius:0}
.webix_item_tab.webix_selected{border-bottom-width:0;background:#fff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#e5f1ff),color-stop(100%,#fff));background:-webkit-linear-gradient(#e5f1ff,#fff);background:-moz-linear-gradient(#e5f1ff,#fff);background:-ms-linear-gradient(top,#e5f1ff,#fff);background:-o-linear-gradient(top,#e5f1ff,#fff)}
.webixtype_bottom .webix_item_tab.webix_selected{border-bottom-width:1px;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background:-webkit-linear-gradient(#ffebc2,#ffdb8f);background:-moz-linear-gradient(#ffebc2,#ffdb8f);background:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_item_tab.webix_selected{border-bottom-width:0;background:#fff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#e5f1ff),color-stop(100%,#fff));background-image:-webkit-linear-gradient(#e5f1ff,#fff);background-image:-moz-linear-gradient(#e5f1ff,#fff);background-image:-ms-linear-gradient(top,#e5f1ff,#fff);background-image:-o-linear-gradient(top,#e5f1ff,#fff)}
.webixtype_bottom .webix_item_tab.webix_selected{border-bottom-width:1px;background-size:100% 100%;background-position:0 0;color:#1e2022;background:#ffdb8f;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ffebc2),color-stop(100%,#ffdb8f));background-image:-webkit-linear-gradient(#ffebc2,#ffdb8f);background-image:-moz-linear-gradient(#ffebc2,#ffdb8f);background-image:-ms-linear-gradient(top,#ffebc2,#ffdb8f);background-image:-o-linear-gradient(top,#ffebc2,#ffdb8f)}
.webix_before_all_tabs{width:100%}
.webix_after_all_tabs{width:100%;border-left:1px solid #a4bed4;border-right:1px solid #a4bed4;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_view.webix_control .webix_disabled_box .webix_item_tab{color:#aaa!important;background:#e9e9e9;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fbfbfb),color-stop(100%,#e9e9e9));background:-webkit-linear-gradient(#fbfbfb,#e9e9e9);background:-moz-linear-gradient(#fbfbfb,#e9e9e9);background:-ms-linear-gradient(top,#fbfbfb,#e9e9e9);background:-o-linear-gradient(top,#fbfbfb,#e9e9e9);border-color:#d5d5d5!important}
.webix_view.webix_control .webix_disabled_box .webix_item_tab{color:#aaa!important;background:#e9e9e9;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fbfbfb),color-stop(100%,#e9e9e9));background-image:-webkit-linear-gradient(#fbfbfb,#e9e9e9);background-image:-moz-linear-gradient(#fbfbfb,#e9e9e9);background-image:-ms-linear-gradient(top,#fbfbfb,#e9e9e9);background-image:-o-linear-gradient(top,#fbfbfb,#e9e9e9);border-color:#d5d5d5!important}
.webix_el_tabbar .webixtype_icon .webix_img_btn{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0 auto;text-align:center}
.webix_el_tabbar .webixtype_icon .webix_img_btn .webix_icon_btn{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0 3px}
.webix_el_tabbar .webixtype_icon .webix_item_tab,.webix_el_tabbar .webixtype_iconTop .webix_item_tab,.webix_el_tabbar .webixtype_image .webix_item_tab{padding:2px 0;border-radius:0}
@ -505,17 +508,17 @@ label.webix_required:after{padding-left:4px;content:"*";color:red}
.webix_menu .webix_list_item .webix_submenu_icon,.webix_menu-x .webix_list_item .webix_submenu_icon{float:right;text-align:right;position:relative;margin-left:4px}
.webix_menu-x .webix_list_item:first-child{margin-left:0}
.webix_menu-x .webix_submenu_icon{top:13px}
.webix_menu-x{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%)}
.webix_menu-x{background-color:#fff;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x}
.webix_menu-x .webix_list_item{display:inline-block;line-height:30px;-moz-background-size:1px 100%,100% 100%,1px 100%;background-size:1px 100%,100% 100%,1px 100%;background-color:transparent;margin:1px 0;background-position:0 0,1px 0,100% 0;background-repeat:no-repeat;background-image:-webkit-gradient(linear,left top,left bottom,#f0f6ff,#fff,#f0f6ff),-webkit-gradient(linear,left top,left bottom,transparent,transparent),-webkit-gradient(linear,left top,left bottom,#f0f6ff,#a4bed4,#f0f6ff);background-image:-webkit-linear-gradient(#f0f6ff,#fff,#f0f6ff),-webkit-linear-gradient(transparent,transparent),-webkit-linear-gradient(#f0f6ff,#a4bed4,#f0f6ff);background-image:-moz-linear-gradient(#f0f6ff,#fff,#f0f6ff),-moz-linear-gradient(transparent,transparent),-moz-linear-gradient(#f0f6ff,#a4bed4,#f0f6ff);background-image:-ms-linear-gradient(top,#f0f6ff,#fff,#f0f6ff),-ms-linear-gradient(transparent,transparent),-ms-linear-gradient(top,#f0f6ff,#a4bed4,#f0f6ff);background-image:-o-linear-gradient(top,#f0f6ff,#fff,#f0f6ff),-o-linear-gradient(transparent,transparent),-o-linear-gradient(top,#f0f6ff,#a4bed4,#f0f6ff)}
.webix_menu-x .webix_list_item:last-child{background-size:1px 100%,100% 100%,1px 100%;background-repeat:no-repeat;background-image:-webkit-gradient(linear,left top,left bottom,#f0f6ff,#fff,#f0f6ff),-webkit-gradient(linear,left top,left bottom,transparent,transparent),-webkit-gradient(linear,left top,left bottom,transparent,transparent);background-image:-webkit-linear-gradient(#f0f6ff,#fff,#f0f6ff),-webkit-linear-gradient(transparent,transparent),-webkit-linear-gradient(transparent,transparent);background-image:-moz-linear-gradient(#f0f6ff,#fff,#f0f6ff),-moz-linear-gradient(transparent,transparent),-moz-linear-gradient(transparent,transparent);background-image:-ms-linear-gradient(top,#f0f6ff,#fff,#f0f6ff),-ms-linear-gradient(transparent,transparent),-ms-linear-gradient(transparent,transparent);background-image:-o-linear-gradient(top,#f0f6ff,#fff,#f0f6ff),-o-linear-gradient(transparent,transparent),-o-linear-gradient(transparent,transparent);border-right:0}
.webix_menu{background:#fff;border:1px solid #a4bed4;border-radius:0}
.webix_menu .webix_list_item{display:block}
.webix_menu .webix_context_separator{height:3px;padding:1px 3px 0}
.webix_menu .webix_context_separator{height:3px;padding:1px 3px 0 3px}
.webix_menu .webix_context_separator .sep_line{height:1px;border-top:1px solid #a4bed4}
.webix_menu .webix_submenu_icon{top:11px}
.webix_menu .webix_context_spacer{height:28px}
.webix_menu_link{color:inherit;text-decoration:none;display:block;height:100%}
.webix_layout_toolbar,.webix_toolbar.webix_layout_subbar{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%)}
.webix_layout_toolbar,.webix_toolbar.webix_layout_subbar{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x}
.webix_toolbar .webix_layout_clean,.webix_toolbar .webix_layout_line,.webix_toolbar .webix_layout_toolbar{background:0 0}
.webix_el_button .webix_hidden_upload,.webix_hidden_upload{height:1px;width:1px;border:0!important;font-size:1px;position:absolute;top:0;left:0;z-index:-1}
.webix_upload_client,.webix_upload_error,.webix_upload_server{width:60px;text-align:center;float:right}
@ -530,29 +533,42 @@ label.webix_required:after{padding-left:4px;content:"*";color:red}
.webix_fieldset fieldset{border:1px solid #81a5c4;margin:0;padding:5px 8px}
.webix_fieldset legend{color:#1e2022;font-size:12px}
.webix_forminput fieldset{border:none;margin:0;padding:0}
.webix_forminput legend{color:#1e2022;line-height:30px;padding:2px 7.5px 2px 2px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:Helvetica,Verdana;float:left}
.webix_slider_box{position:relative;padding:13px 10px 0;height:100%;float:left;border-radius:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:-11px}
.webix_slider_box .webix_slider_left{height:10px;float:left;width:100px;border:1px solid #b5cadc;-webkit-border-radius:5px 0 0 5px;-moz-border-radius-topleft:5px;-moz-border-radius-bottomleft:5px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-radius:5px 0 0 5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_slider_box .webix_slider_right{height:10px;float:left;width:100px;background:#fff;-webkit-border-radius:0 5px 5px 0;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:5px;-moz-border-radius-bottomright:5px;border-radius:0 5px 5px 0;border:1px solid #b5cadc;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_forminput legend{color:#1e2022;line-height:30px;padding:2px 5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:Helvetica,Verdana;float:left;padding-right:7.5px}
.webix_slider_box{position:relative;padding:0 10px;height:100%;padding-top:13px;float:left;border-radius:5px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:-11px}
.webix_slider_box .webix_slider_left{height:10px;float:left;width:100px;border:1px solid #b5cadc;-webkit-border-top-left-radius:5px;-webkit-border-bottom-left-radius:5px;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:0;-moz-border-radius-topleft:5px;-moz-border-radius-bottomleft:5px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0;border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_slider_box .webix_slider_right{height:10px;float:left;width:100px;background:#fff;-webkit-border-top-left-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-right-radius:5px;-webkit-border-bottom-right-radius:5px;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:5px;-moz-border-radius-bottomright:5px;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px;border:1px solid #b5cadc;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.webix_slider_box .webix_slider_handle{z-index:1;position:absolute;width:14px;height:14px;border-radius:8px}
.webix_slider_box .webix_slider_left{background:#f5f9ff}
.webix_slider_box .webix_slider_handle{border:1px solid #a4bed4;-moz-box-shadow:inset 0 1px 1px 1px #fff;-webkit-box-shadow:inset 0 1px 1px 1px #fff;box-shadow:inset 0 1px 1px #fff;background:#fafcff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#d6e8ff),color-stop(100%,#fafcff));background:-webkit-linear-gradient(#d6e8ff,#fafcff);background:-moz-linear-gradient(#d6e8ff,#fafcff);background:-ms-linear-gradient(top,#d6e8ff,#fafcff);background:-o-linear-gradient(top,#d6e8ff,#fafcff);top:10px}
.webix_slider_box .webix_slider_handle{border:1px solid #a4bed4;-moz-box-shadow:inset 0 1px 1px 1px #fff;-webkit-box-shadow:inset 0 1px 1px 1px #fff;box-shadow:inset 0 1px 1px #fff;background:#fafcff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#d6e8ff),color-stop(100%,#fafcff));background-image:-webkit-linear-gradient(#d6e8ff,#fafcff);background-image:-moz-linear-gradient(#d6e8ff,#fafcff);background-image:-ms-linear-gradient(top,#d6e8ff,#fafcff);background-image:-o-linear-gradient(top,#d6e8ff,#fafcff);top:10px}
.webix_rangeslider .webix_slider_box .webix_slider_left{position:absolute}
.webix_rangeslider .webix_slider_box .webix_slider_active{z-index:1}
.webix_rangeslider .webix_slider_box .webix_slider_right{border-radius:5px}
.webix_rangeslider .webix_slider_title_box{position:relative;float:left;width:1px}
.webix_rangeslider .webix_slider_title.webix_slider_move{position:absolute}
.webix_rangeslider.webix_slider_vertical .webix_slider_box .webix_slider_right{-webkit-border-top-left-radius:5px;-webkit-border-bottom-left-radius:5px;-webkit-border-top-right-radius:5px;-webkit-border-bottom-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-bottomleft:5px;-moz-border-radius-topright:5px;-moz-border-radius-bottomright:5px;border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px}
.webix_rangeslider.webix_slider_vertical .webix_slider_title.webix_slider_move{display:block;position:relative}
.webix_slider_alt .webix_slider_box .webix_slider_left,.webix_slider_alt .webix_slider_box .webix_slider_right{border:1px solid #e1e1e1}
.webix_slider_alt .webix_slider_box .webix_slider_handle{width:11px;margin:0 2px;height:14px;border-radius:2px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAICAYAAAAx8TU7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTJCMjdFNENBRTg4MTFFMjk2NjJGMTJENjkyNDA2NTkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTJCMjdFNERBRTg4MTFFMjk2NjJGMTJENjkyNDA2NTkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5MkIyN0U0QUFFODgxMUUyOTY2MkYxMkQ2OTI0MDY1OSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5MkIyN0U0QkFFODgxMUUyOTY2MkYxMkQ2OTI0MDY1OSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Powz/icAAAAaSURBVHjaYmBgYDBjgAA4zcSABQysIECAAQBn+ACx2PqtbAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-position:3px center}
.webix_slider_alt .webix_slider_box .webix_slider_left{background:#f0f6ff}
.webix_slider_alt .webix_slider_box .webix_slider_right{background:#eee}
.webix_slider_alt .webix_slider_box .webix_slider_handle{background-color:#f5f9ff;top:10px}
.webix_slider_vertical .webix_slider_box .webix_slider_left,.webix_slider_vertical .webix_slider_box .webix_slider_right{width:10px;float:none}
.webix_slider_vertical .webix_slider_box .webix_slider_left{-webkit-border-radius:0 0 5px 5px;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:5px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:5px;border-radius:0 0 5px 5px}
.webix_slider_vertical .webix_slider_box .webix_slider_right{-webkit-border-radius:5px 5px 0 0;-moz-border-radius-topleft:5px;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:5px;-moz-border-radius-bottomright:0;border-radius:5px 5px 0 0}
.webix_slider_vertical .webix_slider_box .webix_slider_left{-webkit-border-top-left-radius:0;-webkit-border-bottom-left-radius:5px;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-topleft:0;-moz-border-radius-bottomleft:5px;-moz-border-radius-topright:0;-moz-border-radius-bottomright:5px;border-top-left-radius:0;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:5px}
.webix_slider_vertical .webix_slider_box .webix_slider_right{-webkit-border-top-left-radius:5px;-webkit-border-bottom-left-radius:0;-webkit-border-top-right-radius:5px;-webkit-border-bottom-right-radius:0;-moz-border-radius-topleft:5px;-moz-border-radius-bottomleft:0;-moz-border-radius-topright:5px;-moz-border-radius-bottomright:0;border-top-left-radius:5px;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:0}
.webix_slider_vertical .webix_slider_box .webix_slider_handle{left:7px}
.webix_slider_vertical .webix_slider_title{padding-top:1px;text-align:left}
.webix_slider_vertical.webix_slider_alt .webix_slider_handle{height:11px;width:14px;left:5px;background-position:4px center}
.webix_slider_title{text-align:center}
.webix_slider_title.webix_slider_move{position:relative;text-align:left;display:inline-block;width:auto}
.webix_slider_title.webix_slider_move{position:relative;text-align:left;display:inline-block;width:auto;white-space:nowrap}
.webix_el_box .webix_switch_box{margin-top:4px}
.webix_switch_toggle{position:absolute;visibility:hidden}
.webix_switch_box{display:block;position:relative;cursor:pointer;height:24px;width:60px;background-color:#f1f1f1;border:1px solid #a4bed4;border-radius:60px;box-sizing:border-box;transition:background-color .4s ease;color:#666;text-align:center;float:left}
.webix_el_switch .webix_label_right{display:inline-block;padding-top:3px;margin-top:4px}
.webix_switch_handle{height:22px;width:22px;border-radius:100%;box-shadow:0 1px 5px rgba(0,0,0,.3);border:1px solid #eee;position:absolute;top:0;background-color:#fff;transition:left .3s ease;cursor:pointer;box-sizing:border-box}
.webix_switch_box:active .webix_switch_handle,.webix_switch_handle:focus{box-shadow:0 0 2px 2px rgba(0,0,0,.2)}
.webix_switch_text{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;padding:1px 0 0 18px;display:inline-block;box-sizing:border-box;width:100%}
.webix_switch_on .webix_switch_text{padding:1px 18px 0 0}
.webix_switch_box.webix_switch_on{color:#fff}
.webix_progress_bottom,.webix_progress_top{width:100%;position:absolute;top:0;left:0;height:6px;overflow:hidden;z-index:20}
.webix_progress_bottom{bottom:0;top:auto;height:17px}
.webix_progress_bottom .webix_progress_state,.webix_progress_top .webix_progress_state{width:0;height:6px;background:#ffdb8f;-moz-transition:width 3s;transition:width 3s}
@ -562,7 +578,7 @@ label.webix_required:after{padding-left:4px;content:"*";color:red}
.webix_gage{height:100%;width:100%;transform:rotate(180deg)}
.webix_gage_label{font-size:.9em;text-align:center;margin-top:10px}
.webix_gage_placeholder{margin-top:-20px}
.webix_gage_info{text-align:center;font-size:.7em;position:relative;margin:0 auto 10px}
.webix_gage_info{text-align:center;font-size:.7em;position:relative;margin:0 auto 10px auto}
.webix_gage_min_range{left:-74px}
.webix_gage_max_range{right:-74px}
.webix_gage_max_range,.webix_gage_min_range{display:inline-block;margin-top:20px;position:absolute;text-align:center;width:150px}
@ -571,22 +587,190 @@ label.webix_required:after{padding-left:4px;content:"*";color:red}
.webix_gage_gradient_point_animated{transition:transform 1.3s linear}
.webix_gage_animated{stroke:#0f0;animation:gage_dash 1.3s linear forwards;transition:stroke 1.3s linear,stroke-dasharray 1.3s linear}
.webix_gage_animated_first_load{stroke:#0f0;animation:gage_dash 1.3s linear forwards;transition:stroke 1.3s linear}
@keyframes gage_dash{to{stroke-dashoffset:0}}
@keyframes gage_dash{to{stroke-dashoffset:0}
}
.webix_bullet_name{width:100}
.webix_bullet_header{font-weight:700;font-size:15px}
.webix_bullet_subheader{font-size:15px}
.webix_bullet_scale{font-size:12px;font-weight:700}
.webix_organogram canvas{position:absolute}
.webix_organogram_item{position:absolute;z-index:1;text-align:center;border-radius:4px;background-color:#e3f2fd;border:1px solid #bbdefb;padding:7px 7px 10px;box-sizing:border-box}
.webix_organogram_item{position:absolute;z-index:1;text-align:center;border-radius:4px;background-color:#e3f2fd;border:1px solid #bbdefb;padding:7px 7px 10px 7px;box-sizing:border-box}
.webix_organogram_item.webix_selected{background-color:#ffdb8f;border-color:#ffdb8f}
.webix_organogram_list{border-radius:4px;position:absolute;z-index:1;height:auto;border:1px solid #ddd;box-sizing:border-box}
.webix_organogram_list .webix_organogram_list_item{border:none;text-align:left;position:static;padding:5px;border-radius:0;box-sizing:border-box}
.webix_icon,.webix_icon_btn,.webix_input_icon{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0,0)}
.webix_icon,.webix_input_icon{font-size:17px;display:inline-block;width:20px}
.webix_input_icon{float:right;font-size:19px;color:#888}
.webix_icon_button{background-color:transparent;border:none;padding:0;cursor:pointer;position:relative}
.webix_icon_button .webix_icon{font-size:20px;height:23px;width:21px;display:inline-block;text-align:center;color:#606060}
.webix_icon_btn{font-size:17px;display:inline-block;text-align:center;width:24px;color:#606060}
.webix_el_iconBbutton .webix_icon_btn{text-align:center;width:100%;padding:5px 0}
.webix_el_icon{cursor:pointer}
.webix_badge{background-color:#ff8839;color:#fff;border-radius:50%;font-size:12px;height:22px;min-width:22px;box-sizing:border-box;padding:0 4px;text-align:center;line-height:21px;position:absolute;right:0;top:0}
.webix_list_item .webix_badge{position:static;float:right;margin:4px -5px 0 10px}
.webixtype_base .webix_badge{top:50%;margin-top:-11px;margin-right:8px}
.webix_treemap{background-color:#f5f5f5}
.webix_treemap .webix_scroll_cont{position:relative;height:100%;width:100%}
.webix_treemap_item{position:absolute;color:#444;overflow:hidden;text-align:left;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:3px 5px;border-width:0 1px 1px 0;border-style:solid;border-color:rgba(0,0,0,.2);background:0 0;cursor:pointer}
.webix_treemap_level_top{z-index:1;border-color:rgba(0,0,0,.4)}
.webix_treemap_item_bottom{border-bottom-width:0}
.webix_treemap_item_right{border-right-width:0}
.webix_treemap_item:hover{box-shadow:inset 0 0 5px #666}
.webix_treemap_item.webix_selected{border-color:#ffdb8f;box-shadow:inset 0 0 1px 2px #ffdb8f}
.webix_treemap_header{width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:0 10px;border-bottom:1px solid #a4bed4}
.webix_treemap_header_item{cursor:pointer}
.webix_treemap_header_item:last-child{cursor:default}
.webix_treemap_reset{float:right;width:25px;text-align:center}
.webix_treemap_reset:before{content:"\f00d";color:#1e2022;font-family:FontAwesome;font-size:16px;display:block;cursor:pointer}
.webix_treemap_path_icon{width:20px;text-align:center}
.webix_barcode{position:relative}
.webix_barcode .webix_canvas_text{font-size:13px;padding:0 2px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.portlet_drag{position:absolute;z-index:1;top:5px;right:5px;width:18px;opacity:.5;cursor:pointer}
.portlet_in_drag{opacity:.4}
.portlet_marker,.portlet_markerbottom,.portlet_markerleft,.portlet_markerright,.portlet_markertop{opacity:.5;background:#9169BE;position:absolute;z-index:2;transition:top .5s,left .5s,width .5s,height .5s;top:0;left:0;width:100%;height:100%}
.portlet_markertop{height:50%}
.portlet_markerbottom{height:50%;top:50%}
.portlet_markerleft{width:50%}
.portlet_markerright{width:50%;left:50%}
.panel_icon{position:absolute;z-index:100;top:5px;right:5px;line-height:normal;font-size:13px;width:18px;opacity:.5;cursor:pointer}
.panel_target{position:absolute;background:rgba(120,120,120,.84);box-shadow:0 0 10px 5px #666;z-index:3}
.webix_popup.webix_sidemenu.webix_sidemenu_left{border-width:0 1px 0 0;box-shadow:2px 0 2px rgba(0,0,0,.05)}
.webix_sidemenu_left.webix_animate{transition:left .6s}
.webix_popup.webix_sidemenu.webix_sidemenu_right{left:auto;border-width:0 0 0 1px;box-shadow:-2px 0 2px rgba(0,0,0,.05)}
.webix_sidemenu_right.webix_animate{transition:right .6s}
.webix_popup.webix_sidemenu.webix_sidemenu_top{border-width:0 0 1px 0;box-shadow:0 2px 2px rgba(0,0,0,.05)}
.webix_sidemenu_top .webix_win_body{position:relative}
.webix_sidemenu_top .webix_win_body>.webix_view{position:absolute;top:auto;left:0;bottom:0}
.webix_sidemenu_top.webix_animate,.webix_sidemenu_top.webix_animate .webix_win_body{transition:height .6s}
.webix_popup.webix_sidemenu.webix_sidemenu_bottom{border-width:1px 0 0 0;top:auto;box-shadow:0 -2px 2px rgba(0,0,0,.05)}
.webix_sidemenu_bottom.webix_animate,.webix_sidemenu_bottom.webix_animate .webix_win_body{transition:height .6s}
.webix_sidebar{background:#ECEFF1}
.webix_sidebar .webix_tree_item{color:#454545;height:35px;line-height:35px}
.webix_sidebar .webix_scroll_cont>.webix_tree_leaves{padding:0}
.webix_sidebar .webix_tree_leaves .webix_tree_leaves{margin-left:0}
.webix_sidebar_expanded .webix_tree_item:hover,.webix_sidebar_selected{background-color:rgba(0,0,0,.02)}
.webix_sidebar .webix_tree_item.webix_selected,.webix_sidebar .webix_tree_item.webix_selected span{background-color:#27ae60;padding-right:0}
.webix_sidebar .webix_tree_branch_1 .webix_tree_item{padding-left:40px}
.webix_sidebar .webix_tree_branch_1>.webix_tree_item{height:40px;line-height:40px;padding-left:0}
.webix_sidebar .webix_tree_branch_1{border-bottom:1px solid #e5e5e5}
.webix_sidebar .webix_tree_item span,.webix_sidebar .webix_tree_item.webix_selected span{margin:0;padding:0}
.webix_sidebar_icon{width:40px;text-align:center}
.webix_sidebar_dir_icon{float:right;line-height:inherit}
.webix_sidebar_popup{border:none!important;box-shadow:2px 3px 3px #ddd}
.webix_sidebar_popup,.webix_sidebar_popup .webix_list_item{border-radius:0}
.webix_sidebar_popup_right{box-shadow:-1px 3px 3px #ddd}
.webix_sidebar_popup_list.webix_sidebar_popup_left .webix_icon{float:right;line-height:inherit;width:7px}
.webix_sidebar_popup_title{background:#ECEFF1}
.webix_sidebar_popup_title.webix_selected{border-left-color:#27ae60;background:#27ae60}
.webix_sidebar_popup_title .webix_template{line-height:40px;padding:0 10px;border:1px solid #E5E5E5;border-left:none}
.webix_sidebar_selected.webix_sidebar_popup_title .webix_template{background:rgba(0,0,0,.03);border-left:none}
.webix_sidebar_popup_list .webix_list_item{border-left:1px solid #E5E5E5;border-right:1px solid #E5E5E5}
.webix_sidebar_popup_list .webix_list_item:first-child{border-top:1px solid #E5E5E5}
.webix_sidebar_popup_list .webix_list_item:hover{background:#f6f9fb}
.webix_sidebar_popup_list .webix_list_item.webix_selected:hover{background:#27ae60}
.webix_menu .webix_list_item.webix_sidebar_selected{background:rgba(0,0,0,.02)}
.webix_menu .webix_list_item.webix_sidebar_selected:hover{background:rgba(0,0,0,.02)!important}
.webix_view.webix_pdf{background-color:#404040;overflow:auto;-webkit-overflow-scrolling:touch}
.webix_pdf .canvas_wrapper{margin:0 auto;box-shadow:5px 5px 15px #1c1c1c;width:100%;height:100%}
.webix_toolbar.pdf_bar{background-color:#474747}
.webix_toolbar.pdf_bar .webix_icon_btn{font-size:15px}
.webix_toolbar.pdf_bar .webix_img_btn:focus,.webix_toolbar.pdf_bar .webix_img_btn:hover{background-color:#404040}
.webix_toolbar.pdf_bar .webix_template{background-color:#3498db;color:#fff;line-height:2em}
.webix_toolbar.pdf_bar .webix_el_box input,.webix_toolbar.pdf_bar .webix_inp_static{background-color:#5c5c5c;color:#fff;border-color:#404040}
.webix_toolbar.pdf_bar .webix_el_box input:focus,.webix_toolbar.pdf_bar .webix_inp_static:focus{border-color:#333}
.webix_toolbar.pdf_bar .webix_el_box .webix_input_icon{color:#fff}
.webix_view.webix_popup.pdf_opt_list{box-shadow:5px 5px 15px #1c1c1c;border:none}
.pdf_opt_list .webix_list{background-color:#404040;color:#fff}
.pdf_opt_list .webix_list .webix_list_item{border-color:#474747;line-height:1.5em}
.pdf_opt_list .webix_list .webix_list_item.webix_selected,.pdf_opt_list .webix_list .webix_list_item:hover{color:#404040;background-color:#fff}
.webix_dbllist .webix_list{background:#ededed}
.webix_dbllist .webix_list_item{background:#fff;margin:3px 4px 0 4px;box-sizing:border-box}
.webix_dbllist .webix_list_item.webix_selected{color:#FFF;background:#27ae60}
.webix_dbllist button{width:45%;height:30px;margin-top:5px;background:#fff;border-radius:6px;border:1px solid #a4bed4;cursor:pointer;font-size:13px;font-family:Helvetica,Verdana}
.webix_dbllist button:active{box-shadow:inset 1px 1px 0 silver}
.webix_dbllist button .webix_icon{color:#888;font-size:26px}
.webix_dbllist button:first-child{margin-top:32px;margin-right:5%}
.webix_dbllist button:last-child{margin-left:5%}
.webix_dbllist .bottom_label{font-size:10px;text-transform:uppercase;background:#ededed;padding-left:13px}
.webix_invalid .webix_list{background:#f8e2e2}
.webix_toolbar .webix_el_label,.webix_toolbar .webix_inp_label{color:#1e2022}
.webix_ss_sort_asc{position:absolute;float:right;right:3px;top:8px;width:7px;height:13px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAANCAYAAABlyXS1AAAARUlEQVR4nGNgQAKGxib/GbABkIS7b8B/DAUwCRiGK0CXwFBAb1DfP/U/LszwHwi2X7qFgUEArBtdAVwCBmAKMCSQFSDzAWXXaOHsXeqkAAAAAElFTkSuQmCC)}
.webix_ss_sort_desc{position:absolute;right:3px;top:8px;width:7px;height:13px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAANCAYAAABlyXS1AAAARUlEQVR42mNgQAL1/VP/M2ADIIntF2/9x1AAlrh0C47hCmA60DFYwX88gIFGwNDY5D8uDFbg7hvwHx2jmIBTAlkB0e4BAEjlaNtBWJPnAAAAAElFTkSuQmCC)}
.webix_group_back .webix_arrow_icon{color:#1e2022}
.webix_menu-x .webix_list_item:active,.webix_menu-x .webix_list_item:focus,.webix_menu-x .webix_list_item:hover{background-color:rgba(255,255,255,.4)!important}
.webix_menu .webix_list_item:active,.webix_menu .webix_list_item:hover{background-color:rgba(0,0,0,.05)!important}
.webix_list_item .webix_submenu_icon{width:0;height:0;border-width:4px;border-style:solid}
.webix_menu-x .webix_list_item .webix_submenu_icon{border-color:#375975 transparent transparent transparent}
.webix_menu .webix_list_item .webix_submenu_icon{border-color:transparent transparent transparent #375975}
.webix_popup_title{color:#1e2022!important;background:#e3e3e3!important;font-size:15px!important;font-weight:700;border-bottom:1px solid #dedede!important;text-shadow:none!important}
.webix_modal_box{background:#ebebeb!important;border:1px solid #a4bed4!important}
.confirmButton{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x}
.confirmButtonActive{background:#fff}
.webix_item_tab{font-size:13px}
.buttonStyle{font-size:13px;font-family:Helvetica,Verdana}
.activeShadow{box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}
.webix_img_btn_abs:active+input,.webix_inp_counter_next:active,.webix_inp_counter_prev:active,.webixtype_base:active{background:#f5f5f5;box-shadow:inset 0 3px 5px rgba(0,0,0,.125);background-repeat:none}
.webix_icon_button:active,.webix_img_btn:active,.webix_img_btn_top:active{box-shadow:inset 0 3px 5px rgba(0,0,0,.125);background-color:rgba(0,0,0,.05)}
.webix_pressed .webix_img_btn_abs+input,.webix_pressed .webixtype_base{box-shadow:inset 0 3px 5px rgba(0,0,0,.125);background:#f5f5f5!important}
.webix_slider_vertical .webix_slider_box{margin-top:-8px}
.webix_rangeslider .webix_slider_title_box{height:17px}
.webix_switch_box.webix_switch_on{background-color:#a4bed4}
.webix_switch_text{line-height:21px}
.webix_accordionitem_label .webix_icon{font-size:19px;width:25px}
.webix_accordionitem.vertical>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAARUlEQVR42o2PAQYAMAwD9+iEFvTpnZYZU7EQRa4kaxKAXD9y9yTZluCBALRJpATNrIG6rAdjjmBVeCuB6EyAYkNEiDE33yMJRSaycR8/AAAAAElFTkSuQmCC);background-repeat:no-repeat}
.webix_accordionitem.vertical.collapsed>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAASElEQVR42n2PMQoAMAgD++gEdPLpFkshS9oDEcxlcA1V1euNcpI9k5m2MPfrqABCBS8KBptAR8QJZks0kGjgjMQn/oc/AKy4Acp9RSZl+HEYAAAAAElFTkSuQmCC);background-repeat:no-repeat}
.webix_accordionitem.horizontal>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAALCAYAAACzkJeoAAAASUlEQVR42p2QMQoAQQgD79EZ0Mqn5xCu2cPdYgUbJ0rMMxXgLeiuKq8gsJAz8weQ0QiwJEfECnr4wdlEnwJ68+yyhReC+c85oRecj0Um+pmo9wAAAABJRU5ErkJggg==);background-repeat:no-repeat}
.webix_accordionitem.horizontal:last-child>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAALCAYAAACzkJeoAAAARElEQVR42qXPsQoAIAhF0T76PdDJT7cUmtQhcmk4N8QVQ9JXN2bmgWOgqp+BiCRG2AYAMoi3/LxYdyagAnhA6G93TrABZaJFJjrFY8IAAAAASUVORK5CYII=);background-repeat:no-repeat}
.webix_accordionitem.horizontal.collapsed:last-child>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAASElEQVR42n2PMQoAMAgD++gEdPLpFkshS9oDEcxlcA1V1euNcpI9k5m2MPfrqABCBS8KBptAR8QJZks0kGjgjMQn/oc/AKy4Acp9RSZl+HEYAAAAAElFTkSuQmCC);background-repeat:no-repeat}
.webix_accordionitem.horizontal.collapsed>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAARUlEQVR42o2PAQYAMAwD9+iEFvTpnZYZU7EQRa4kaxKAXD9y9yTZluCBALRJpATNrIG6rAdjjmBVeCuB6EyAYkNEiDE33yMJRSaycR8/AAAAAElFTkSuQmCC);background-repeat:no-repeat}
.webix_progress_bottom,.webix_progress_top{background:#f7f7f7;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#f2f2f2),color-stop(50%,#f7f7f7),color-stop(100%,#f2f2f2));background-image:-webkit-linear-gradient(top,#f2f2f2 0,#f7f7f7 50%,#f2f2f2 100%);background-image:-moz-linear-gradient(top,#f2f2f2 0,#f7f7f7 60%,#f2f2f2 100%);background-image:-ms-linear-gradient(top,#f2f2f2 0,#f7f7f7 60%,#f2f2f2 100%);background-image:-o-linear-gradient(top,#f2f2f2 0,#f7f7f7 60%,#f2f2f2 100%);background-position:0 1px;background-repeat:repeat-x}
.webix_daterange .webix_range_timepicker .webix_cal_time{padding:5px 15px}
.webix_daterange .webix_range_footer .webix_template{padding:10px 0}
.webix_cal_range{background-color:#fff4dc}
.webix_item_tab .webix_icon{width:30px;font-size:19px}
.webix_tab_more_icon{border-bottom:1px solid #a4bed4}
.webix_skin_mark{height:110px}
.webix_sparklines{padding:1px 0;box-sizing:border-box}
.webix_sparklines svg{box-sizing:border-box}
.webix_sparklines_line{stroke:#3498db;stroke-width:1;fill:transparent;stroke-linecap:round}
.webix_sparklines_item{fill:#3498db;stroke-width:1}
.webix_sparklines_bar{fill:#6dbcf0}
.webix_sparklines_bar_negative{fill:#d86c79}
.webix_sparklines_area{fill:#e5eef4}
.webix_sparklines_origin{stroke:#888;stroke-width:1}
.webix_sparklines_event_area{fill:transparent}
.webix_sparklines_area_chart .webix_sparklines_event_area:hover,.webix_sparklines_line_chart .webix_sparklines_event_area:hover,.webix_sparklines_splinearea_chart .webix_sparklines_event_area:hover{fill:rgba(220,220,220,.4);stroke:rgba(255,255,255,.6)}
.webix_sparklines_bar_chart .webix_sparklines_event_area:hover,.webix_sparklines_pie_chart .webix_sparklines_event_area:hover{fill:rgba(255,255,255,.3)}
.webix_ui_print{display:none}
body.webix_print{margin-top:0}
@media print{body.webix_print{overflow:visible!important;background-color:none!important}
body.webix_print>*{display:none}
body.webix_print *{visibility:hidden}
.webix_ui_print{display:block!important;margin:0!important;visibility:visible!important}
.webix_ui_print *{visibility:visible!important}
.webix_print_noscroll{height:auto!important;width:auto!important}
.webix_print_noscroll,.webix_print_noscroll .webix_scroll_cont{overflow:visible!important}
.webix_print_pagebreak{page-break-after:always}
.webix_print_footer,.webix_print_header{display:block!important;margin:20px 0;text-align:center;height:auto!important;visibility:visible!important}
.webix_print_footer *,.webix_print_header *{visibility:visible!important}
.webix_table_print{display:table;visibility:visible!important;table-layout:fixed;width:100%;border:1px solid #ebebeb;margin-bottom:20px;position:initial}
.webix_table_print td{overflow:hidden}
.webix_table_print tr{page-break-inside:avoid}
.webix_table_print .webix_cell{display:table-cell!important;border-right:1px solid #ebebeb;border-bottom:1px solid #ebebeb;padding:0 10px;white-space:nowrap}
.webix_table_print .webix_header_cell{display:table-cell;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:#e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff));background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-position:0 1px;background-repeat:repeat-x;border-right:1px solid #a4bed4;border-bottom:1px solid #a4bed4}
.webix_table_print .webix_footer_cell{display:table-cell;background:#fafafa;border-right:1px solid #ebebeb;border-top:1px solid #ebebeb;border-bottom:1px solid #ebebeb}
.webix_table_print .webix_cell.webix_dtable_span{position:initial!important;white-space:normal}
.webix_table_print .webix_rotate{transform-origin:center 40%!important;-webkit-transform-origin:center 40%!important}
.webix_table_print.borderless,.webix_table_print.borderless .webix_cell{border:none}
.webix_table_print.webix_view.webix_list-x{white-space:normal}
.webix_table_print.webix_view.webix_list-x .webix_list_item{display:table-cell}
}
/*!
* Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
@font-face{font-family:FontAwesome;src:url(../fonts/fontawesome-webfont.eot?v=4.7.0);src:url(../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0) format('embedded-opentype'),url(../fonts/fontawesome-webfont.woff2?v=4.7.0) format('woff2'),url(../fonts/fontawesome-webfont.woff?v=4.7.0) format('woff'),url(../fonts/fontawesome-webfont.ttf?v=4.7.0) format('truetype'),url(../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular) format('svg');font-weight:400;font-style:normal}
.fa,.webix_icon,.webix_icon_btn,.webix_input_icon{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0,0)}
.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0,0)}
.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}
.fa-2x{font-size:2em}
.fa-3x{font-size:3em}
@ -597,7 +781,7 @@ label.webix_required:after{padding-left:4px;content:"*";color:red}
.fa-ul>li{position:relative}
.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}
.fa-li.fa-lg{left:-1.85714286em}
.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}
.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}
.fa-pull-left{float:left}
.fa-pull-right{float:right}
.fa.fa-pull-left{margin-right:.3em}
@ -609,9 +793,11 @@ label.webix_required:after{padding-left:4px;content:"*";color:red}
.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}
.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}
@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}
100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}
}
@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}
100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}
}
.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}
.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}
.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}
@ -1300,140 +1486,6 @@ label.webix_required:after{padding-left:4px;content:"*";color:red}
.fa-meetup:before{content:"\f2e0"}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}
.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}
.webix_icon,.webix_input_icon{font-size:17px;display:inline-block;width:20px}
.webix_input_icon{float:right;font-size:19px;color:#888}
.webix_icon_button{background-color:transparent;border:none;padding:0;cursor:pointer;position:relative}
.webix_icon_button .webix_icon{font-size:20px;height:23px;width:21px;display:inline-block;text-align:center;color:#606060}
.webix_icon_btn{font-size:17px;display:inline-block;text-align:center;width:24px;color:#606060}
.webix_el_iconBbutton .webix_icon_btn{text-align:center;width:100%;padding:5px 0}
.webix_el_icon{cursor:pointer}
.webix_badge{background-color:#ff8839;color:#fff;border-radius:50%;font-size:12px;height:22px;min-width:22px;box-sizing:border-box;padding:0 4px;text-align:center;line-height:21px;position:absolute;right:0;top:0}
.webix_list_item .webix_badge{position:static;float:right;margin:4px -5px 0 10px}
.webixtype_base .webix_badge{top:50%;margin-top:-11px;margin-right:8px}
.webix_treemap{background-color:#f5f5f5}
.webix_treemap .webix_scroll_cont{position:relative;height:100%;width:100%}
.webix_treemap_item{position:absolute;color:#444;overflow:hidden;text-align:left;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:3px 5px;border-width:0 1px 1px 0;border-style:solid;border-color:rgba(0,0,0,.2);background:0 0}
.webix_treemap_level_top{z-index:1;border-color:rgba(0,0,0,.4)}
.webix_treemap_item_bottom{border-bottom-width:0}
.webix_treemap_item_right{border-right-width:0}
.webix_treemap_item:hover{box-shadow:inset 0 0 5px #666}
.webix_treemap_item.webix_selected{border-color:#ffdb8f;box-shadow:inset 0 0 1px 2px #ffdb8f}
.webix_treemap_header{width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:0 10px;border-bottom:1px solid #a4bed4}
.webix_treemap_header_item{cursor:pointer}
.webix_treemap_header_item:last-child{cursor:default}
.webix_treemap_reset{float:right;width:25px;text-align:center}
.webix_treemap_reset:before{content:"\f00d";color:#1e2022;font-family:FontAwesome;font-size:16px;display:block;cursor:pointer}
.webix_treemap_path_icon{width:20px;text-align:center}
.webix_barcode{position:relative}
.webix_barcode .webix_canvas_text{font-size:13px;padding:0 2px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
.portlet_drag{position:absolute;z-index:1;top:5px;right:5px;width:18px;opacity:.5;cursor:pointer}
.portlet_in_drag{opacity:.4}
.portlet_marker,.portlet_markerbottom,.portlet_markerleft,.portlet_markerright,.portlet_markertop{opacity:.5;background:#9169BE;position:absolute;transition:top .5s,left .5s,width .5s,height .5s;top:0;left:0;width:100%;height:100%}
.portlet_markertop{height:50%}
.portlet_markerbottom{height:50%;top:50%}
.portlet_markerleft{width:50%}
.portlet_markerright{width:50%;left:50%}
.webix_popup.webix_sidemenu.webix_sidemenu_left{border-width:0 1px 0 0;box-shadow:2px 0 2px rgba(0,0,0,.05)}
.webix_sidemenu_left.webix_animate{transition:left .6s}
.webix_popup.webix_sidemenu.webix_sidemenu_right{left:auto;border-width:0 0 0 1px;box-shadow:-2px 0 2px rgba(0,0,0,.05)}
.webix_sidemenu_right.webix_animate{transition:right .6s}
.webix_popup.webix_sidemenu.webix_sidemenu_top{border-width:0 0 1px;box-shadow:0 2px 2px rgba(0,0,0,.05)}
.webix_sidemenu_top .webix_win_body{position:relative}
.webix_sidemenu_top .webix_win_body>.webix_view{position:absolute;top:auto;left:0;bottom:0}
.webix_sidemenu_top.webix_animate,.webix_sidemenu_top.webix_animate .webix_win_body{transition:height .6s}
.webix_popup.webix_sidemenu.webix_sidemenu_bottom{border-width:1px 0 0;top:auto;box-shadow:0 -2px 2px rgba(0,0,0,.05)}
.webix_sidemenu_bottom.webix_animate,.webix_sidemenu_bottom.webix_animate .webix_win_body{transition:height .6s}
.webix_view.webix_pdf{background-color:#404040;overflow:auto;-webkit-overflow-scrolling:touch}
.webix_pdf .canvas_wrapper{margin:0 auto;box-shadow:5px 5px 15px #1c1c1c;width:100%;height:100%}
.webix_toolbar.pdf_bar{background-color:#474747}
.webix_toolbar.pdf_bar .webix_icon_btn{font-size:15px}
.webix_toolbar.pdf_bar .webix_img_btn:focus,.webix_toolbar.pdf_bar .webix_img_btn:hover{background-color:#404040}
.webix_toolbar.pdf_bar .webix_template{background-color:#3498db;color:#fff;line-height:2em}
.webix_toolbar.pdf_bar .webix_el_box input,.webix_toolbar.pdf_bar .webix_inp_static{background-color:#5c5c5c;color:#fff;border-color:#404040}
.webix_toolbar.pdf_bar .webix_el_box input:focus,.webix_toolbar.pdf_bar .webix_inp_static:focus{border-color:#333}
.webix_toolbar.pdf_bar .webix_el_box .webix_input_icon{color:#fff}
.webix_view.webix_popup.pdf_opt_list{box-shadow:5px 5px 15px #1c1c1c;border:none}
.pdf_opt_list .webix_list{background-color:#404040;color:#fff}
.pdf_opt_list .webix_list .webix_list_item{border-color:#474747;line-height:1.5em}
.pdf_opt_list .webix_list .webix_list_item.webix_selected,.pdf_opt_list .webix_list .webix_list_item:hover{color:#404040;background-color:#fff}
.webix_dbllist .webix_list{background:#ededed}
.webix_dbllist .webix_list_item{background:#fff;margin:3px 4px 0;box-sizing:border-box}
.webix_dbllist .webix_list_item.webix_selected{color:#FFF;background:#27ae60}
.webix_dbllist button{width:45%;height:30px;margin-top:5px;background:#fff;border-radius:6px;border:1px solid #a4bed4;cursor:pointer;font-size:13px;font-family:Helvetica,Verdana}
.webix_dbllist button:active{box-shadow:inset 1px 1px 0 silver}
.webix_dbllist button .webix_icon{color:#888;font-size:26px}
.webix_dbllist button:first-child{margin-top:32px;margin-right:5%}
.webix_dbllist button:last-child{margin-left:5%}
.webix_dbllist .bottom_label{font-size:10px;text-transform:uppercase;background:#ededed;padding-left:13px}
.webix_invalid .webix_list{background:#f8e2e2}
.webix_toolbar .webix_el_label,.webix_toolbar .webix_inp_label{color:#1e2022}
.webix_ss_sort_asc{position:absolute;float:right;right:3px;top:8px;width:7px;height:13px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAANCAYAAABlyXS1AAAARUlEQVR4nGNgQAKGxib/GbABkIS7b8B/DAUwCRiGK0CXwFBAb1DfP/U/LszwHwi2X7qFgUEArBtdAVwCBmAKMCSQFSDzAWXXaOHsXeqkAAAAAElFTkSuQmCC)}
.webix_ss_sort_desc{position:absolute;right:3px;top:8px;width:7px;height:13px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAANCAYAAABlyXS1AAAARUlEQVR42mNgQAL1/VP/M2ADIIntF2/9x1AAlrh0C47hCmA60DFYwX88gIFGwNDY5D8uDFbg7hvwHx2jmIBTAlkB0e4BAEjlaNtBWJPnAAAAAElFTkSuQmCC)}
.webix_group_back .webix_arrow_icon{color:#1e2022}
.webix_menu-x .webix_list_item:active,.webix_menu-x .webix_list_item:focus,.webix_menu-x .webix_list_item:hover{background-color:rgba(255,255,255,.4)!important}
.webix_menu .webix_list_item:active,.webix_menu .webix_list_item:hover{background-color:rgba(0,0,0,.05)!important}
.webix_list_item .webix_submenu_icon{width:0;height:0;border-width:4px;border-style:solid}
.webix_menu-x .webix_list_item .webix_submenu_icon{border-color:#375975 transparent transparent}
.webix_menu .webix_list_item .webix_submenu_icon{border-color:transparent transparent transparent #375975}
.webix_popup_title{color:#1e2022!important;background:#e3e3e3!important;font-size:15px!important;font-weight:700;border-bottom:1px solid #dedede!important;text-shadow:none!important}
.webix_modal_box{background:#ebebeb!important;border:1px solid #a4bed4!important}
.confirmButton{color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%)}
.confirmButtonActive{background:#fff}
.webix_item_tab{font-size:13px}
.buttonStyle{font-size:13px;font-family:Helvetica,Verdana}
.activeShadow{box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}
.webix_img_btn_abs:active+input,.webix_inp_counter_next:active,.webix_inp_counter_prev:active,.webixtype_base:active{background:none #f5f5f5;box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}
.webix_icon_button:active,.webix_img_btn:active,.webix_img_btn_top:active{box-shadow:inset 0 3px 5px rgba(0,0,0,.125);background-color:rgba(0,0,0,.05)}
.webix_pressed .webix_img_btn_abs+input,.webix_pressed .webixtype_base{box-shadow:inset 0 3px 5px rgba(0,0,0,.125);background:#f5f5f5!important}
.webix_slider_vertical .webix_slider_box{margin-top:-8px}
.webix_accordionitem_label .webix_icon{font-size:19px;width:25px}
.webix_accordionitem.vertical>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAARUlEQVR42o2PAQYAMAwD9+iEFvTpnZYZU7EQRa4kaxKAXD9y9yTZluCBALRJpATNrIG6rAdjjmBVeCuB6EyAYkNEiDE33yMJRSaycR8/AAAAAElFTkSuQmCC);background-repeat:no-repeat}
.webix_accordionitem.vertical.collapsed>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAASElEQVR42n2PMQoAMAgD++gEdPLpFkshS9oDEcxlcA1V1euNcpI9k5m2MPfrqABCBS8KBptAR8QJZks0kGjgjMQn/oc/AKy4Acp9RSZl+HEYAAAAAElFTkSuQmCC);background-repeat:no-repeat}
.webix_accordionitem.horizontal>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAALCAYAAACzkJeoAAAASUlEQVR42p2QMQoAQQgD79EZ0Mqn5xCu2cPdYgUbJ0rMMxXgLeiuKq8gsJAz8weQ0QiwJEfECnr4wdlEnwJ68+yyhReC+c85oRecj0Um+pmo9wAAAABJRU5ErkJggg==);background-repeat:no-repeat}
.webix_accordionitem.horizontal:last-child>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAALCAYAAACzkJeoAAAARElEQVR42qXPsQoAIAhF0T76PdDJT7cUmtQhcmk4N8QVQ9JXN2bmgWOgqp+BiCRG2AYAMoi3/LxYdyagAnhA6G93TrABZaJFJjrFY8IAAAAASUVORK5CYII=);background-repeat:no-repeat}
.webix_accordionitem.horizontal.collapsed:last-child>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAASElEQVR42n2PMQoAMAgD++gEdPLpFkshS9oDEcxlcA1V1euNcpI9k5m2MPfrqABCBS8KBptAR8QJZks0kGjgjMQn/oc/AKy4Acp9RSZl+HEYAAAAAElFTkSuQmCC);background-repeat:no-repeat}
.webix_accordionitem.horizontal.collapsed>.webix_accordionitem_header .webix_accordionitem_button{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAARUlEQVR42o2PAQYAMAwD9+iEFvTpnZYZU7EQRa4kaxKAXD9y9yTZluCBALRJpATNrIG6rAdjjmBVeCuB6EyAYkNEiDE33yMJRSaycR8/AAAAAElFTkSuQmCC);background-repeat:no-repeat}
.webix_progress_bottom,.webix_progress_top{background:0 1px repeat-x #f7f7f7;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#f2f2f2),color-stop(50%,#f7f7f7),color-stop(100%,#f2f2f2)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#f2f2f2 0,#f7f7f7 50%,#f2f2f2 100%);background-image:-moz-linear-gradient(top,#f2f2f2 0,#f7f7f7 60%,#f2f2f2 100%);background-image:-ms-linear-gradient(top,#f2f2f2 0,#f7f7f7 60%,#f2f2f2 100%);background-image:-o-linear-gradient(top,#f2f2f2 0,#f7f7f7 60%,#f2f2f2 100%)}
.webix_daterange .webix_range_timepicker .webix_cal_time{padding:5px 15px}
.webix_daterange .webix_range_footer .webix_template{padding:10px 0}
.webix_cal_range{background-color:#fff4dc}
.webix_item_tab .webix_icon{width:30px;font-size:19px}
.webix_tab_more_icon{border-bottom:1px solid #a4bed4}
.webix_skin_mark{height:110px}
.webix_sparklines{padding:1px 0;box-sizing:border-box}
.webix_sparklines svg{box-sizing:border-box}
.webix_sparklines_line{stroke:#3498db;stroke-width:1;fill:transparent;stroke-linecap:round}
.webix_sparklines_item{fill:#3498db;stroke-width:1}
.webix_sparklines_bar{fill:#6dbcf0}
.webix_sparklines_bar_negative{fill:#d86c79}
.webix_sparklines_area{fill:#e5eef4}
.webix_sparklines_origin{stroke:#888;stroke-width:1}
.webix_sparklines_event_area{fill:transparent}
.webix_sparklines_area_chart .webix_sparklines_event_area:hover,.webix_sparklines_line_chart .webix_sparklines_event_area:hover,.webix_sparklines_splinearea_chart .webix_sparklines_event_area:hover{fill:rgba(220,220,220,.4);stroke:rgba(255,255,255,.6)}
.webix_sparklines_bar_chart .webix_sparklines_event_area:hover,.webix_sparklines_pie_chart .webix_sparklines_event_area:hover{fill:rgba(255,255,255,.3)}
.webix_ui_print{display:none}
body.webix_print{margin-top:0}
@media print{body.webix_print{overflow:visible!important;background-color:none!important}
body.webix_print>*{display:none}
body.webix_print *{visibility:hidden}
.webix_ui_print{display:block!important;margin:0!important;visibility:visible!important}
.webix_ui_print *{visibility:visible!important}
.webix_print_noscroll{height:auto!important;width:auto!important}
.webix_print_noscroll,.webix_print_noscroll .webix_scroll_cont{overflow:visible!important}
.webix_print_pagebreak{page-break-after:always}
.webix_print_footer,.webix_print_header{display:block!important;margin:20px 0;text-align:center;height:auto!important;visibility:visible!important}
.webix_print_footer *,.webix_print_header *{visibility:visible!important}
.webix_table_print{display:table;visibility:visible!important;table-layout:fixed;width:100%;border:1px solid #ebebeb;margin-bottom:20px;position:initial}
.webix_table_print td{overflow:hidden}
.webix_table_print tr{page-break-inside:avoid}
.webix_table_print .webix_cell{display:table-cell!important;border-right:1px solid #ebebeb;border-bottom:1px solid #ebebeb;padding:0 10px;white-space:nowrap}
.webix_table_print .webix_header_cell{display:table-cell;color:#1e2022!important;box-shadow:0 1px 1px #fff inset;background:0 1px repeat-x #e5f1ff;background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eaf3ff),color-stop(50%,#e5f1ff),color-stop(100%,#d6e8ff)) 0 1px repeat-x;background-image:-webkit-linear-gradient(top,#eaf3ff 0,#e5f1ff 50%,#d6e8ff 100%);background-image:-moz-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-ms-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);background-image:-o-linear-gradient(top,#eaf3ff 0,#e5f1ff 60%,#d6e8ff 100%);border-right:1px solid #a4bed4;border-bottom:1px solid #a4bed4}
.webix_table_print .webix_footer_cell{display:table-cell;background:#fafafa;border-right:1px solid #ebebeb;border-top:1px solid #ebebeb;border-bottom:1px solid #ebebeb}
.webix_table_print .webix_cell.webix_dtable_span{position:initial!important;white-space:normal}
.webix_table_print .webix_rotate{transform-origin:center 40%!important;-webkit-transform-origin:center 40%!important}
.webix_table_print.borderless,.webix_table_print.borderless .webix_cell{border:none}
.webix_table_print.webix_view.webix_list-x{white-space:normal}
.webix_table_print.webix_view.webix_list-x .webix_list_item{display:table-cell}}
.webix_strong{font-weight:700;white-space:nowrap}
.webix_light{color:#666d73}
.webix_debug div{border:1px solid orange;background-color:#FF9;color:#000}

View File

@ -47,6 +47,20 @@
font-size: 125%;
}
.link_default {
font-weight: bold;
color: #610B0B;
text-decoration: none;
}
.link_default:hover {text-decoration:underline;}
.link_forum {
font-weight: bold;
color: #610B0B;
text-decoration: none;
}
.link_forum:hover {text-decoration:underline;}
.delete {
text-align: center;
font-weight: bold;

View File

@ -0,0 +1,519 @@
@page{
size: Letter;
margin: 0.5cm;
background-color: white !important;
}
@media print {
thead {display: table-header-group;}
body {
background-color: #fff;
}
}
.emisor-cintilla{
background-color: #975759;
color: #fff;
}
.fiscales-emisor{
color: #7d1916;
}
.fiscales-emisor .telefono, .fiscales-emisor .correo, .fiscales-emisor .web{
color: #333;
}
header .titulo-vertical{
background-color: #dbc5c6;
color: #000;
}
.receptor .nombre{
color: #000;
}
.receptor .rfc{
color: #000;
}
.receptor .direccion{
color: #000;
}
.receptor .estado{
color: #000;
}
.cfdi .folio span{
color: #ed483d;
}
.cfdi .tipo span{
color: #ed483d;
}
.cfdi .folio-fiscal span{
color: #ed483d;
}
.conceptos th{
background-color: #975759;
}
.conceptos td.clave, .conceptos td.unidad, .conceptos td.valor-unitario{
background-color: #dbc5c6;
}
.conceptos td.descripcion, .conceptos td.cantidad, .conceptos td.importe{
background-color: #f0e7e7;
}
table.subtotal th{
background-color: #dbc5c6;
}
table.subtotal td{
background-color: #f0e7e7;
}
.sello .cadenas-sello .cadena div {
background-color: #dbc5c6;
color: #7d1916;
}
.rfc-pac {
background-color: #dbc5c6;
color: #7d1916;
}
.cancelada{
color: #ed3833;
}
@font-face {
font-family: 'Avenir Next';
src: url('/static/fonts/avenir_next/AvenirNextLTPro-Regular.eot');
src: url('/static/fonts/avenir_next/AvenirNextLTPro-Regular.eot?#iefix') format('embedded-opentype'),
url('/static/fonts/avenir_next/AvenirNextLTPro-Regular.woff2') format('woff2'),
url('/static/fonts/avenir_next/AvenirNextLTPro-Regular.woff') format('woff'),
url('/static/fonts/avenir_next/AvenirNextLTPro-Regular.ttf') format('truetype'),
url('/static/fonts/avenir_next/AvenirNextLTPro-Regular.svg#AvenirNextLTPro-Regular') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Avenir Next';
src: url('/static/fonts/avenir_next/AvenirNextLTPro-Bold.eot');
src: url('/static/fonts/avenir_next/AvenirNextLTPro-Bold.eot?#iefix') format('embedded-opentype'),
url('/static/fonts/avenir_next/AvenirNextLTPro-Bold.woff2') format('woff2'),
url('/static/fonts/avenir_next/AvenirNextLTPro-Bold.woff') format('woff'),
url('/static/fonts/avenir_next/AvenirNextLTPro-Bold.ttf') format('truetype'),
url('/static/fonts/avenir_next/AvenirNextLTPro-Bold.svg#AvenirNextLTPro-Bold') format('svg');
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: 'Avenir Next';
src: url('/static/fonts/avenir_next/AvenirNextLTPro-It.eot');
src: url('/static/fonts/avenir_next/AvenirNextLTPro-It.eot?#iefix') format('embedded-opentype'),
url('/static/fonts/avenir_next/AvenirNextLTPro-It.woff2') format('woff2'),
url('/static/fonts/avenir_next/AvenirNextLTPro-It.woff') format('woff'),
url('/static/fonts/avenir_next/AvenirNextLTPro-It.ttf') format('truetype'),
url('/static/fonts/avenir_next/AvenirNextLTPro-It.svg#AvenirNextLTPro-It') format('svg');
font-weight: normal;
font-style: italic;
}
body {
/*
font-family: 'Avenir Next';
*/
}
#plantilla {
border: 1px solid #fff;
border-color: rgb(204,204,204);
background: #fff;
display: block;
margin: 0 auto;
width: 19.5cm;
height: 25.9cm;
position: relative;
}
.cancelada{
-ms-transform: rotate(320deg);
-webkit-transform: rotate(320deg);
transform: rotate(320deg);
color: #ed3833;
font-size: 100px;
font-weight: bold;
left: 18%;
position: absolute;
text-align: center;
top: 30%;
z-index: 1000;
}
.cancelada div{
font-size: 20px;
}
.emisor-cintilla{
background-color: #975759;
color: #fff;
font-size: 7pt;
padding: 5px;
text-align: center;
}
.datos-emisor .logo{
margin-left: 20px;
max-width: 180px;
}
.datos-emisor .fiscales-emisor{
float: right;
}
.fiscales-emisor{
color: #7d1916;
font-weight: bold;
margin-top: 20px;
text-align: right;
}
.fiscales-emisor .nombre{
font-size: 18px;
padding-right: 30px;
}
.fiscales-emisor .rfc{
font-size: 16px;
padding-right: 30px;
}
.fiscales-emisor .regimen{
font-size: 12px;
padding-right: 30px;
}
.fiscales-emisor .telefono, .fiscales-emisor .correo, .fiscales-emisor .web{
color: #333;
font-size: 14px;
line-height: 15px;
padding-right: 10px;
}
.fiscales-emisor img{
margin-left: 10px;
width: 10px;
}
.clear{
clear: both;
}
header .titulo-vertical{
background-color: #dbc5c6;
-ms-transform: rotate(270deg);
-webkit-transform: rotate(270deg);
transform: rotate(270deg);
font-size: 15px;
font-weight: bold;
left: -31px;
line-height: 35px;
position: absolute;
text-align: center;
top: 35px;
width: 105px;
}
header .receptor{
box-sizing: border-box;
float: left;
font-size: 10px;
height: 106px;
margin-top: 10px;
position: relative;
padding-bottom: 5px;
padding-left: 45px;
padding-top: 5px;
width: 60%;
}
.receptor .nombre{
color: #000;
font-size: 17px;
font-weight: bold;
}
.receptor .rfc{
color: #000;
font-size: 15px;
font-weight: bold;
}
.receptor .direccion,
.receptor .estado{
color: #000;
font-size: 10px;
}
.receptor img{
width: 10px;
}
.receptor .correo,
.receptor .telefono{
float: right;
width: 40%;
}
.receptor .uso-cfdi{
color: #000;
font-size: 12px;
font-weight: bold;
float: left;
width: 60%;
}
header .cfdi{
box-sizing: border-box;
float: right;
font-size: 10px;
height: 100px;
margin-top: 10px;
position: relative;
padding-bottom: 5px;
padding-left: 45px;
padding-top: 5px;
width: 35%;
}
.cfdi .folio, .cfdi .tipo{
color: #000;
float: left;
font-size: 11px;
font-weight: bold;
line-height: 15px;
width: 50%;
}
.cfdi .folio span, .cfdi .tipo span{
color: #ed483d;
}
.cfdi .folio span{
font-size: 10px;
}
.cfdi .tipo span{
font-size: 10px;
}
.cfdi .folio-fiscal{
color: #000;
font-size: 9px;
font-weight: bold;
line-height: 15px;
text-align: center;
}
.cfdi .folio-fiscal span{
color: #ed483d;
}
.cfdi .fecha-emision, .cfdi .fecha-certificacion, .cfdi .lugar-expedicion{
color: #333;
font-size: 10px;
font-weight: bold;
line-height: 15px;
}
.conceptos{
margin-bottom: 10px;
margin-top: 20px;
width: 100%;
text-align: center;
}
.conceptos th{
background-color: #975759;
color: #fff;
font-size: 11px;
line-height: 15px;
}
.conceptos .clave{
width: 10%;
}
.conceptos .descripcion{
width: 45%;
}
.conceptos .descripcion div{
text-align: justify;
}
.conceptos .unidad{
width: 8%;
}
.conceptos .cantidad{
width: 9%;
}
.conceptos .valor-unitario{
width: 13%;
}
.conceptos .importe{
width: 15%;
}
.conceptos td{
background-color: #975759;
color: #000;
font-size: 11px;
line-height: 15px;
}
.conceptos td.clave, .conceptos td.unidad, .conceptos td.valor-unitario{
background-color: #dbc5c6;
}
.conceptos td.descripcion, .conceptos td.cantidad, .conceptos td.importe{
background-color: #f0e7e7;
}
.conceptos td.valor-unitario, .conceptos td.importe{
text-align: right;
}
.total-letras{
float: left;
font-size: 12px;
line-height: 15px;
margin: 5px 0;
width: 63%;
}
table.subtotal{
float: right;
font-size: 12px;
line-height: 15px;
text-align: right;
width: 37%;
font-weight: bold;
}
table.subtotal th{
background-color: #f0e7e7;
width: 60%;
padding: 3px 3px 3px 3px;
}
table.subtotal td{
background-color: #dbc5c6;
width: 40%;
padding: 3px 3px 3px 3px;
}
.condiciones-pago{
font-size: 11px;
line-height: 14px;
}
.notas{
float: left;
font-size: 11px;
margin: 20px 0;
width: 70%;
}
.formapago-metodopago, .moneda-tipocambio, .tiporelacion, .relacionados{
float: left;
font-size: 11px;
line-height: 12px;
width: 70%;
}
.factura-info{
float: left;
font-size: 11px;
line-height: 13px;
width: 70%;
}
.tipocomite, .tipoproceso, .idcontabilidad{
float: right;
font-size: 10px;
line-height: 12px;
width: 20%;
}
.sello{
margin: 10px 0;
}
.sello .cbb{
border: 1px solid #000;
height: auto;
margin-top: 10px;
margin-right: 1px;
width: 18%;
}
.sello .cadenas-sello{
color: #000;
float: right;
font-size: 8px;
font-weight: bold;
line-height: 15px;
width: 79%;
margin-left: 5px;
margin-right: 5px;
word-break: break-all;
}
.sello .cadenas-sello .cadena{
margin: 5px 0;
}
.sello .cadenas-sello .cadena div{
font-weight: normal;
background-color: #dbc5c6;
color: #7d1916;
}
.cadena-original{
color: #000;
float: right;
font-size: 8px;
font-weight: bold;
line-height: 15px;
width: 99%;
margin: 5px;
word-break: break-all;
}
.cadena-original div{
font-weight: normal;
background-color: #dbc5c6;
color: #7d1916;
}
.rfc-pac{
background-color: #dbc5c6;
color: #7d1916;
font-size: 10px;
line-height: 15px;
text-align: center;
margin: 5px;
}

View File

@ -1,95 +0,0 @@
/* SideBar*/
.webix_sidebar{
background: #ECEFF1;
}
.webix_sidebar .webix_tree_item {
color: #454545;
height: 35px;
line-height: 35px;
}
.webix_sidebar .webix_scroll_cont > .webix_tree_leaves {
padding: 0;
}
.webix_sidebar .webix_tree_leaves .webix_tree_leaves {
margin-left: 0px;
}
.webix_sidebar_selected,
.webix_sidebar_expanded .webix_tree_item:hover{
background-color: rgba(0,0,0,0.02);
}
.webix_sidebar .webix_tree_item.webix_selected,
.webix_sidebar .webix_tree_item.webix_selected span{
background-color: #27ae60;
padding-right:0;
}
.webix_sidebar .webix_tree_branch_1 .webix_tree_item{
padding-left:40px;
}
.webix_sidebar .webix_tree_branch_1>.webix_tree_item{
height: 40px;
line-height: 40px;
padding-left:0;
}
.webix_sidebar .webix_tree_branch_1{
border-bottom:1px solid #e5e5e5;
}
.webix_sidebar .webix_tree_item.webix_selected span,
.webix_sidebar .webix_tree_item span{
margin:0;
padding:0px;
}
.webix_sidebar_icon{
width: 40px;
text-align: center;
}
.webix_sidebar_dir_icon{
float: right;
line-height: inherit;
}
/*SubMenu (Popup) */
.webix_sidebar_popup{
border:none !important;
box-shadow: 2px 3px 3px #ddd;
}
.webix_sidebar_popup, .webix_sidebar_popup .webix_list_item{
border-radius:0;
}
.webix_sidebar_popup_right{
box-shadow: -1px 3px 3px #ddd;
}
/*SubMenu: title*/
.webix_sidebar_popup_title{
background: #ECEFF1;
}
.webix_sidebar_popup_title.webix_selected{
border-left-color: #27ae60;
background: #27ae60;
}
.webix_sidebar_popup_title .webix_template{
line-height: 40px;
padding: 0 10px;
border: 1px solid #E5E5E5;
border-left:none;
}
.webix_sidebar_selected.webix_sidebar_popup_title .webix_template{
background: rgba(0,0,0,0.03);
border-left: none;
}
.webix_sidebar_popup_list .webix_list_item{
border-left: 1px solid #E5E5E5;
border-right: 1px solid #E5E5E5;
}
/*SubMenu: list*/
.webix_sidebar_popup_list .webix_list_item:first-child{
border-top: 1px solid #E5E5E5;
}
.webix_sidebar_popup_list .webix_list_item:hover{
background: #f6f9fb;
}
.webix_sidebar_popup_list .webix_list_item.webix_selected:hover{
background: #27ae60;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 754 B

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
source/static/img/web.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ function configuracion_inicial(){
var values = data.json()
show('cmd_ir_al_admin', values)
})
webix.ajax().get('/values/main', function(text, data){
webix.ajax().sync().get('/values/main', function(text, data){
var values = data.json()
$$('lbl_title_main').setValue(values.empresa)
var pos = 4
@ -36,8 +36,16 @@ function configuracion_inicial(){
$$('cmd_update_timbres').define('badge', values.timbres)
$$('cmd_update_timbres').refresh()
add_config({'key': 'decimales_precios', 'value': values.decimales_precios})
add_config({'key': 'used_cfdi_pays', 'value': values.pagos})
add_config({'key': 'multi_currency', 'value': values.multi_currency})
add_config({'key': 'pays_data_bank', 'value': values.pays_data_bank})
add_config({'key': 'show_filter_by_day', 'value': values.show_filter_by_day})
})
get_way_payment()
}
@ -108,16 +116,19 @@ function menu_user_click(id, e, node){
function current_dates(){
var fy = $$('filter_year')
var fm = $$('filter_month')
var fd = $$('filter_day')
var pfy = $$('prefilter_year')
var pfm = $$('prefilter_month')
var d = new Date()
fy.blockEvent()
fm.blockEvent()
fd.blockEvent()
pfy.blockEvent()
pfm.blockEvent()
fm.setValue(d.getMonth() + 1)
fd.setValue(d.getDate())
pfm.setValue(d.getMonth() + 1)
webix.ajax().sync().get('/values/filteryears', function(text, data){
var values = data.json()
@ -129,6 +140,7 @@ function current_dates(){
fy.unblockEvent()
fm.unblockEvent()
fd.unblockEvent()
pfy.unblockEvent()
pfm.unblockEvent()
}
@ -215,4 +227,4 @@ function cmd_update_timbres_click(){
$$('cmd_update_timbres').define('badge', value)
$$('cmd_update_timbres').refresh()
})
}
}

View File

@ -12,12 +12,15 @@ var nomina_controllers = {
$$('cmd_nomina_without_stamp').attachEvent('onItemClick', cmd_nomina_without_stamp_click)
$$('cmd_nomina_delete').attachEvent('onItemClick', cmd_nomina_delete_click)
$$('cmd_nomina_timbrar').attachEvent('onItemClick', cmd_nomina_timbrar_click)
$$('cmd_nomina_sat').attachEvent('onItemClick', cmd_nomina_sat_click)
$$('cmd_nomina_log').attachEvent('onItemClick', cmd_nomina_log_click)
$$('cmd_nomina_download').attachEvent('onItemClick', cmd_nomina_download_click)
$$('cmd_nomina_cancel').attachEvent('onItemClick', cmd_nomina_cancel_click)
$$('grid_nomina').attachEvent('onItemClick', grid_nomina_click)
$$('filter_year_nomina').attachEvent('onChange', filter_year_nomina_change)
$$('filter_month_nomina').attachEvent('onChange', filter_month_nomina_change)
$$('filter_dates_nomina').attachEvent('onChange', filter_dates_nomina_change)
$$('grid_nomina').attachEvent('onSelectChange', grid_nomina_on_select_change)
webix.extend($$('grid_nomina'), webix.ProgressBar)
}
}
@ -252,10 +255,10 @@ function up_employees_upload_complete(response){
function delete_empleado(id){
webix.ajax().del('/employees', {id: id}, function(text, xml, xhr){
var msg = 'Empleado eliminado correctamente'
if (xhr.status == 200){
if(xhr.status == 200){
$$('grid_employees').remove(id);
msg_ok(msg)
} else {
}else{
msg = 'El Empleado tiene recibos timbrados'
msg_error(msg)
}
@ -389,6 +392,42 @@ function timbrar_nomina(){
}
function send_mail(row){
if(!row.uuid){
msg_error('La nómina no esta timbrada')
return
}
var data = {'opt': 'send_mail', 'id': row.id}
msg = '¿Estás seguro de enviar por correo este Recibo de Nómina?'
webix.confirm({
title: 'Enviar Recibo de Nómina',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
webix.ajax().post('/nomina', data, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico'
msg_error(msg)
},
success:function(text, data, XmlHttpRequest){
values = data.json();
if(values.ok){
msg_ok(values.msg)
}else{
msg_error(values.msg)
}
}
})
}
}
})
}
function grid_nomina_click(id, e, node){
var row = this.getItem(id)
@ -396,8 +435,8 @@ function grid_nomina_click(id, e, node){
location = '/doc/nomxml/' + row.id
}else if(id.column == 'pdf'){
window.open('/doc/nompdf/' + row.id, '_blank')
//~ }else if(id.column == 'email'){
//~ enviar_correo(row)
}else if(id.column == 'email'){
send_mail(row)
}
}
@ -446,29 +485,43 @@ function cmd_nomina_cancel_click(){
return
}
msg = '¿Estás seguro de cancelar el recibo?<BR><BR>'
msg += row['empleado'] + ' (' + row['serie'] + '-' + row['folio'] + ')'
msg += '<BR><BR>ESTA ACCIÓN NO SE PUEDE DESHACER<BR><BR>'
webix.confirm({
title: 'Cancelar Nomina',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if (result){
cancel_nomina(row['id'])
}
}
})
win_invoice_cancel_nomina.init()
$$('win_invoice_cancel_nomina').show()
}
function cancel_nomina(id){
function cmd_win_cancel_nomina_close_click(){
$$('win_invoice_cancel_nomina').close()
}
function cmd_invoice_cancel_nomina_click(){
var reason = $$('lst_reasons_cancel').getValue()
var uuid = $$('txt_cancel_uuid').getValue()
if(!reason){
msg = 'Selecciona un motivo para esta cancelación'
msg_error(msg)
return
}
if(reason=='01' & !uuid){
msg = 'Debes de capturar el UUID que reemplaza a este CFDI'
msg_error(msg)
return
}
$$('win_invoice_cancel_nomina').close()
send_cancel_nomina(reason, uuid)
}
function send_cancel_nomina(reason, uuid){
var grid = $$('grid_nomina')
var row = grid.getSelectedItem()
var data = new Object()
data['opt'] = 'cancel'
data['id'] = id
data['id'] = row.id
data['args'] = {reason: reason, uuid: uuid}
webix.ajax().sync().post('nomina', data, {
error:function(text, data, XmlHttpRequest){
@ -478,7 +531,7 @@ function cancel_nomina(id){
success:function(text, data, XmlHttpRequest){
values = data.json();
if(values.ok){
grid.updateItem(id, values.row)
grid.updateItem(row.id, values.row)
msg_ok(values.msg)
}else{
msg_error(values.msg)
@ -490,4 +543,85 @@ function cancel_nomina(id){
function cmd_nomina_log_click(){
location = '/doc/nomlog/0'
}
}
function cmd_nomina_download_click(){
var grid = $$('grid_nomina')
if(!grid.count()){
msg = 'Sin documentos a descargar'
msg_error(msg)
return
}
var ids = []
grid.eachRow(function(row){
var r = grid.getItem(row)
ids.push(r.id)
})
var filters = {'by': 'download', 'ids': ids}
webix.ajax().response('blob').get('/nomina', filters, function(text, data){
webix.html.download(data, 'nomina.zip');
});
}
function grid_nomina_on_select_change(){
var g = $$('grid_nomina')
var rows = g.getSelectedItem(true)
var total = 0
for (i = 0; i < rows.length; i++) {
if(typeof(rows[i].total) == 'string'){
total += rows[i].total.to_float()
}else{
total += rows[i].total
}
}
g.getColumnConfig('empleado').footer[0].text = webix.i18n.priceFormat(total)
g.refreshColumns()
}
function cmd_nomina_sat_click(){
var g = $$('grid_nomina')
if(g.count() == 0){
return
}
var row = g.getSelectedItem()
if (row == undefined){
msg_error('Selecciona un recibo de nómina')
return
}
if (row instanceof Array){
msg_error('Selecciona solo un recibo de nómina')
return
}
if(!row.uuid){
msg_error('La factura no esta timbrada, solo es posible consultar \
el estatus en el SAT de facturas timbradas')
return
}
var options = {opt: 'status_sat', id: row.id}
webix.ajax().get('/nomina', options, function(text, data){
var value = data.json()
if(value == 'Vigente'){
msg_ok(value)
}else if(value == 'uncancel'){
ask_invoice_uncancel(row.id)
}else{
msg_error(value)
}
})
}

View File

@ -1,15 +1,33 @@
//~ Empresa Libre
//~ Copyright (C) 2016-2018 Mauricio Baeza Servin (web@correolibre.net)
//~
//~ This program is free software: you can redistribute it and/or modify
//~ it under the terms of the GNU General Public License as published by
//~ the Free Software Foundation, either version 3 of the License, or
//~ (at your option) any later version.
//~
//~ This program is distributed in the hope that it will be useful,
//~ but WITHOUT ANY WARRANTY; without even the implied warranty of
//~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//~ GNU General Public License for more details.
//~
//~ You should have received a copy of the GNU General Public License
//~ along with this program. If not, see <http://www.gnu.org/licenses/>.
var cfg_partners = new Object()
var partners_controllers = {
init: function(){
$$('cmd_new_partner').attachEvent('onItemClick', cmd_new_partner_click);
$$('cmd_new_contact').attachEvent('onItemClick', cmd_new_contact_click);
//~ $$('cmd_new_contact').attachEvent('onItemClick', cmd_new_contact_click);
$$('cmd_edit_partner').attachEvent('onItemClick', cmd_edit_partner_click);
$$('cmd_delete_partner').attachEvent('onItemClick', cmd_delete_partner_click);
$$('cmd_save_partner').attachEvent('onItemClick', cmd_save_partner_click);
$$('cmd_cancel_partner').attachEvent('onItemClick', cmd_cancel_partner_click);
$$('cmd_cancel_contact').attachEvent('onItemClick', cmd_cancel_contact_click);
$$('cmd_partner_zero').attachEvent('onItemClick', cmd_partner_zero_click);
//~ $$('cmd_cancel_contact').attachEvent('onItemClick', cmd_cancel_contact_click);
//~ $$('cmd_partner_zero').attachEvent('onItemClick', cmd_partner_zero_click);
$$('codigo_postal').attachEvent('onKeyPress', postal_code_key_press);
$$('codigo_postal').attachEvent('onTimedKeyPress', postal_code_key_up);
$$('colonia').attachEvent('onFocus', colonia_on_focus)
@ -18,12 +36,33 @@ var partners_controllers = {
$$("es_proveedor").attachEvent( "onChange", is_supplier_change)
$$("rfc").attachEvent( "onBlur", rfc_lost_focus)
$$('multi').attachEvent('onViewChange', multi_change)
$$('grid_partners').attachEvent('onItemDblClick', cmd_edit_partner_click)
$$('grid_partners').attachEvent('onSelectChange', grid_partners_on_select_change)
$$('grid_partners').attachEvent('onItemDblClick', grid_partners_double_click)
//~ $$('grid_partners').attachEvent('onSelectChange', grid_partners_on_select_change)
$$('partner_balance').attachEvent('onChange', partner_balance_on_change)
$$('cmd_partner_add_account_bank').attachEvent('onItemClick', cmd_partner_add_account_bank_click)
$$('grid_partner_account_bank').attachEvent('onItemClick', grid_partner_account_bank_click)
default_config_partners()
}
}
function default_config_partners(){
webix.ajax().get('/config', {'fields': 'partners'}, {
error: function(text, data, xhr) {
msg = 'Error al consultar'
msg_error(msg)
},
success: function(text, data, xhr) {
var values = data.json()
cfg_partners = values
//~ show('cmd_partner_zero', cfg_partners['chk_config_change_balance_partner'])
}
})
}
function get_condicion_pago(){
webix.ajax().get('/values/condicionespago', {
error: function(text, data, xhr) {
@ -38,8 +77,12 @@ function get_condicion_pago(){
function cmd_new_partner_click(id, e, node){
$$('form_partner').clearValidation()
$$('form_partner_account_bank').clearValidation()
$$('form_partner').setValues({
id: 0, pais: 'México', tipo_persona: 1, es_activo: true})
id: 0, pais: 'México', tipo_persona: 1, es_activo: true,
partner_balance: 0.00})
$$('forma_pago').getList().load('/values/formapago')
get_condicion_pago()
$$('grid_partners').clearSelection()
@ -49,6 +92,10 @@ function cmd_new_partner_click(id, e, node){
get_uso_cfdi_to_table()
query = table_usocfdi.chain().find({fisica: true}).data()
$$('lst_uso_cfdi_socio').getList().parse(query)
$$('partner_balance').define('readonly', !cfg_partners['chk_config_change_balance_partner'])
get_partner_banks()
get_partner_accounts_bank(0)
get_sat_regimenes()
}
@ -62,6 +109,8 @@ function cmd_edit_partner_click(){
var msg = ''
var row = $$('grid_partners').getSelectedItem()
$$('form_partner_account_bank').clearValidation()
if (row == undefined){
msg = 'Selecciona un Socio de Negocio'
msg_error(msg)
@ -75,14 +124,20 @@ function cmd_edit_partner_click(){
},
success: function(text, data, xhr){
var values = data.json()
$$('form_partner').clearValidation()
$$('form_partner').setValues(values)
$$('forma_pago').getList().load('/values/formapago')
$$('partner_balance').define('readonly', !cfg_partners['chk_config_change_balance_partner'])
get_uso_cfdi_to_table()
if(values.tipo_persona == 1){
query = table_usocfdi.chain().find({fisica: true}).data()
get_sat_regimenes()
}else if(values.tipo_persona == 2){
query = table_usocfdi.chain().find({moral: true}).data()
get_sat_regimenes(true)
}else{
query = [{id: 'P01', value: 'Por definir'}]
}
@ -93,12 +148,17 @@ function cmd_edit_partner_click(){
if(values.es_proveedor){
$$('cuenta_proveedor').enable()
}
get_partner_accounts_bank(row['id'])
pause(250)
$$('lst_receptor_regimenes_fiscales').select(values.regimenes)
}
})
$$('multi_partners').setValue('partners_new')
$$('tab_partner').setValue('Datos Fiscales')
};
get_partner_banks()
}
function cmd_delete_partner_click(id, e, node){
@ -156,6 +216,13 @@ function cmd_save_partner_click(id, e, node){
var values = form.getValues();
if(!values.rfc){
msg = 'Captura el RFC'
msg_error(msg)
$$('tab_partner').setValue('Datos Fiscales')
return
}
if(values.tipo_persona != 4){
if(values.codigo_postal && values.codigo_postal.length != 5){
msg = 'Longitud inválida del C.P.'
@ -179,6 +246,18 @@ function cmd_save_partner_click(id, e, node){
}
}
var ids_regimenes = $$('lst_receptor_regimenes_fiscales').getSelectedId()
if(values.tipo_persona < 3){
if(!ids_regimenes){
msg = 'Selecciona al menos un Regimen Fiscal'
msg_error(msg)
return
}
}
values['accounts'] = $$('grid_partner_account_bank').data.getRange()
values['regimenes'] = ids_regimenes
webix.ajax().post('/partners', values, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico';
@ -281,18 +360,28 @@ function opt_tipo_change(new_value, old_value){
$$('id_fiscal').define('value', '')
show('id_fiscal', new_value == 4)
$$('lst_receptor_regimenes_fiscales').clearAll()
var regimen_616 = {id: 11, value: '[616] Sin obligaciones fiscales'}
if (new_value == 1 || new_value == 2){
$$("rfc").define("value", "")
$$("rfc").define("readonly", false)
moral = false
if(new_value == 2){
moral = true
}
get_sat_regimenes(moral)
} else if (new_value == 3) {
$$("rfc").define("value", RFC_PUBLICO)
$$("nombre").define("value", PUBLICO)
$$("rfc").define("readonly", true)
$$('lst_receptor_regimenes_fiscales').parse(regimen_616)
} else if (new_value == 4) {
$$("rfc").define("value", RFC_EXTRANJERO)
$$("rfc").define("readonly", true)
$$("pais").define("readonly", false)
$$("pais").define("value", "")
$$('lst_receptor_regimenes_fiscales').parse(regimen_616)
}
$$("nombre").refresh();
@ -310,10 +399,12 @@ function opt_tipo_change(new_value, old_value){
}else if (new_value == 2){
query = table_usocfdi.chain().find({moral: true}).data()
}else{
query = [{id: 'P01', value: 'Por definir'}]
query = [{id: 'S01', value: '[S01] Sin efectos fiscales. '}]
}
$$('lst_uso_cfdi_socio').getList().parse(query)
$$('lst_uso_cfdi_socio').refresh()
}
@ -337,57 +428,6 @@ function is_supplier_change(new_value, old_value){
}
function partner_reset_saldo(id){
webix.ajax().post('/partners', {opt: 'reset', id: id}, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico';
msg_error(msg)
},
success:function(text, data, XmlHttpRequest){
var values = data.json();
if(values.ok){
msg = 'Saldo actualizado correctamente'
$$('grid_partners').updateItem(id, {saldo_cliente: 0.0})
$$('cmd_partner_zero').disable()
msg_ok(msg)
}
}
})
}
function cmd_partner_zero_click(){
var g = $$('grid_partners')
var row = g.getSelectedItem()
var saldo = row.saldo_cliente.to_float()
if(saldo){
msg = '¿Estas seguro de poner en cero el saldo del cliente?<BR><BR>'
msg += 'ESTA ACCIÓN NO SE PUEDE DESHACER'
webix.confirm({
title: 'Saldo Cliente',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if (result){
partner_reset_saldo(row.id)
}
}
})
}else{
$$('cmd_partner_zero').disable()
}
}
function grid_partners_on_select_change(){
$$('cmd_partner_zero').enable()
}
function rfc_lost_focus(prev_view){
//~ var form = this.getFormView()
//~ var values = form.getValues()
@ -430,3 +470,199 @@ function multi_partners_change(prevID, nextID){
}
function grid_partners_double_click(id, e, node){
//~ if(id.column!='saldo_cliente'){
cmd_edit_partner_click()
//~ }
}
function partner_balance_on_change(new_value, old_value){
if(!isFinite(new_value)){
this.config.value = old_value
this.refresh()
}
}
function cmd_partner_add_account_bank_click(){
var form = $$('form_partner_account_bank')
if (!form.validate()){
msg = 'Valores inválidos'
msg_error(msg)
return
}
var values = form.getValues()
var id_partner = $$('form_partner').getValues().id
var account = {
id_partner: id_partner,
delete: '-',
banco: $$('lst_partner_bank').getText(),
cuenta: values.partner_account.trim(),
clabe: values.partner_clabe.trim(),
}
if(!account.cuenta){
msg = 'La cuenta es requerida'
msg_error(msg)
return
}
if(!account.cuenta.is_number()){
msg = 'Solo digitos en la cuenta'
msg_error(msg)
return
}
if(account.cuenta.length < 10){
msg = 'Longitud incorrecta de la cuenta'
msg_error(msg)
return
}
if(!account.clabe){
msg = 'La CLABE es requerida'
msg_error(msg)
return
}
if(account.clabe.length != 18){
msg = 'La CLABE debe ser de 18 digitos'
msg_error(msg)
return
}
if(!account.clabe.is_number()){
msg = 'Solo digitos en la CLABE'
msg_error(msg)
return
}
var grid = $$('grid_partner_account_bank')
if(id_partner){
partner_new_account_bank(account, grid)
}else{
grid.add(account)
}
form.setValues({})
}
function get_partner_banks(){
webix.ajax().get('/satbancos', {opt: 'active'}, function(text, data){
var values = data.json()
$$('lst_partner_bank').getList().parse(values)
})
}
function partner_new_account_bank(account, grid){
webix.ajax().post('/socioscb', {opt: 'new', values: account}, {
error: function(text, data, xhr) {
msg = 'Error al guardar'
msg_error(msg)
},
success: function(text, data, xhr) {
var values = data.json()
if(values.ok){
account['id'] = values.id
grid.add(account)
msg_ok(values.msg)
}else{
msg_error(values.msg)
}
}
})
}
function get_partner_accounts_bank(id_partner){
var grid = $$('grid_partner_account_bank')
grid.clearAll()
if(id_partner){
var data = {opt: 'by_partner', id_partner: id_partner}
webix.ajax().get('/socioscb', data, {
error: function(text, data, xhr) {
msg = 'Error al consultar'
msg_error(msg)
},
success: function(text, data, xhr) {
var values = data.json()
grid.parse(values)
}
})
}
}
function grid_partner_account_bank_click(id, e, node){
if(id.column != 'delete'){
return
}
var id_partner = $$('form_partner').getValues().id
var grid = $$('grid_partner_account_bank')
var msg = '¿Estás seguro de eliminar la cuenta de banco seleccionada?<BR><BR>'
msg += 'ESTA ACCION NO SE PUEDE DESHACER'
webix.confirm({
title: 'Eliminar cuenta de banco',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if (result){
if(id_partner){
partner_delete_account_bank(id.row)
}else{
grid.remove(id.row)
}
}
}
})
}
function partner_delete_account_bank(row){
var grid = $$('grid_partner_account_bank')
webix.ajax().post('/socioscb', {opt: 'delete', values: {id: row}}, {
error: function(text, data, xhr) {
msg = 'Error al eliminar'
msg_error(msg)
},
success: function(text, data, xhr) {
var values = data.json()
if(values.ok){
grid.remove(row)
msg_ok(values.msg)
}else{
msg_error(values.msg)
}
}
})
}
function get_sat_regimenes(morales=false){
var data = {opt: 'actives', morales: morales}
webix.ajax().sync().get('/satregimenes', data, {
error: function(text, data, xhr) {
msg = 'Error al consultar'
msg_error(msg)
},
success: function(text, data, xhr) {
var values = data.json()
$$('lst_receptor_regimenes_fiscales').clearAll()
$$('lst_receptor_regimenes_fiscales').parse(values)
}
})
}

View File

@ -1,8 +1,9 @@
var cfg_products = new Object()
var gis_admin = false
function products_default_config(){
webix.ajax().get('/config', {'fields': 'productos'}, {
webix.ajax().get('/config', {'fields': 'main_products'}, {
error: function(text, data, xhr) {
msg = 'Error al consultar'
msg_error(msg)
@ -18,8 +19,26 @@ function products_default_config(){
if(cfg_products['inventario']){
$$('grid_products').showColumn('existencia')
}
//~ show('cant_by_packing', values.chk_use_packing)
show('cmd_show_exists', values.chk_multi_stock)
}
})
webix.ajax().get('/users', {'opt': 'is_admin'}, {
error: function(text, data, xhr) {
msg = 'Error al consultar'
msg_error(msg)
},
success: function(text, data, xhr) {
var values = data.json()
gis_admin = values.is_admin
if(values.is_admin){
$$('cmd_add_inventory').show()
//~ $$('cmd_products_add').show()
}
}
})
}
@ -31,6 +50,12 @@ var products_controllers = {
$$("cmd_save_product").attachEvent("onItemClick", cmd_save_product_click)
$$("cmd_cancel_product").attachEvent("onItemClick", cmd_cancel_product_click)
$$("cmd_import_products").attachEvent("onItemClick", cmd_import_products_click)
$$("cmd_add_inventory").attachEvent("onItemClick", cmd_add_inventory_click)
$$("cmd_products_add").attachEvent("onItemClick", cmd_products_add_click)
$$('cmd_add_products_from_xml').attachEvent('onItemClick', cmd_add_products_from_xml_click)
$$('cmd_show_exists').attachEvent('onItemClick', cmd_show_exists_click)
$$('cmd_save_products_add').attachEvent('onItemClick', cmd_save_products_add_click)
$$('cmd_close_products_add').attachEvent('onItemClick', cmd_close_products_add_click)
$$("chk_automatica").attachEvent("onChange", chk_automatica_change)
$$("valor_unitario").attachEvent("onChange", valor_unitario_change)
$$('precio_con_impuestos').attachEvent('onChange', precio_con_impuestos_change)
@ -98,6 +123,7 @@ function cmd_edit_product_click(){
get_taxes()
$$('unidad').getList().load('/values/unidades')
configurar_producto()
var grid = $$('grid_products')
var row = grid.getSelectedItem()
if(row == undefined){
@ -106,9 +132,10 @@ function cmd_edit_product_click(){
}
$$('categoria').getList().load('/values/categorias')
webix.ajax().get('/products', {id:row['id']}, {
webix.ajax().get('/products', {id: row['id']}, {
error: function(text, data, xhr) {
msg_error()
msg_error(text)
},
success: function(text, data, xhr){
var values = data.json()
@ -205,10 +232,6 @@ function cmd_save_product_click(id, e, node){
}
var rows = $$('grid_product_taxes').getSelectedId(true, true)
if (rows.length == 0){
msg_error('Selecciona un impuesto')
return
}
var values = form.getValues();
@ -222,7 +245,19 @@ function cmd_save_product_click(id, e, node){
return
}
if(values['objeto_impuesto']=='01' && rows.length > 0){
msg = 'Si Objeto de Impuestos = 01, no debes seleccionar ningún impuesto'
msg_error(msg)
return
}
if(values['objeto_impuesto']=='02' && rows.length == 0){
msg = 'Si Objeto de Impuestos = 02, debes de seleccionar al menos un impuesto'
msg_error(msg)
return
}
values['taxes'] = JSON.stringify(rows)
webix.ajax().sync().post('products', values, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico'
@ -241,9 +276,7 @@ function cmd_save_product_click(id, e, node){
function cmd_cancel_product_click(id, e, node){
$$("multi_products").setValue("products_home")
};
@ -422,4 +455,537 @@ function up_products_upload_complete(response){
}
}
})
}
}
//~ Add inventory
function cmd_add_inventory_click(id, e, node){
var row = $$('grid_products').getSelectedItem()
if (row == undefined){
msg_error('Selecciona un Producto')
return
}
win_add_inventory.init()
$$('txt_add_id').setValue(row.id)
$$('txt_add_key').setValue(row.clave)
$$('txt_add_unit').setValue(row.unidad)
$$('txt_add_description').setValue(row.descripcion)
$$('lst_warehouses').getList().load('/warehouse?opt=for_select')
$$('win_add_inventory').show()
}
//~ Show details inventory
function cmd_show_exists_click(id, e, node){
var row = $$('grid_products').getSelectedItem()
if (row == undefined){
msg_error('Selecciona un Producto')
return
}
win_show_exists.init()
$$('txt_id_product').setValue(row.id)
$$('grid_warehouse_exists').load('warehouseproduct?opt=by_product&id=' + row.id)
if(gis_admin){
$$('lst_warehouse_target').getList().load('/warehouse?opt=for_select')
}else{
$$('lbl_title_move').hide()
$$('txt_cant_to_move').hide()
$$('lst_warehouse_target').hide()
$$('cmd_warehouse_move').hide()
}
$$('win_show_exists').show()
}
function cmd_warehouse_move_click(id, e, node){
var id_product = $$('txt_id_product').getValue()
var row = $$('grid_warehouse_exists').getSelectedItem()
if (row == undefined){
msg_error('Selecciona un Almacen origen')
return
}
var warehouse_source = row.id
var cant_to_move = $$('txt_cant_to_move').getValue()
var warehouse_target = $$('lst_warehouse_target').getValue()
if(!cant_to_move){
msg_error('La cantidad no puede ser cero')
return
}
if(cant_to_move > row.exists){
msg_error('La cantidad a mover no puede ser mayor a la existencia')
return
}
if (warehouse_target == ''){
msg_error('Selecciona un Almacen destino')
return
}
if (warehouse_source == warehouse_target){
msg_error('Los almacenes origen y destino deben ser diferentes')
return
}
var values = {
id_product: id_product,
cant: cant_to_move,
source: warehouse_source,
target: warehouse_target
}
msg = '¿Estás seguro de hacer este movimiento?'
webix.confirm({
title: 'Movimiento de Almacen',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
_warehouse_movement(values)
}
}
})
}
function _warehouse_movement(args){
var values = {
opt: 'warehouse_movement',
values: args,
}
webix.ajax().sync().post('inventoryentries', values, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico'
msg_error(msg)
},
success:function(text, data, XmlHttpRequest){
var values = data.json();
if (values.ok) {
$$('txt_cant_to_move').setValue(0)
$$('lst_warehouse_target').setValue('')
$$('grid_warehouse_exists').load('warehouseproduct?opt=by_product&id=' + args.id_product)
$$('grid_warehouse_exists').clearSelection()
msg_ok('Movimiento realizado correctamente')
}else{
msg_error(values.msg)
}
}
})
}
function cmd_win_show_exists_close_click(id, e, node){
$$('win_show_exists').close()
}
//~ Add products
function cmd_products_add_click(id, e, node){
$$("multi_products").setValue("product_add")
cfg_products['partner_id'] = 0
cfg_products['partner_rfc'] = ''
}
//~ Close add products
function cmd_close_products_add_click(id, e, node){
var grid = $$('grid_partner_products')
$$('multi_invoices').setValue('products_home')
$$('lbl_partner').setValue('')
grid.clearAll()
}
function _add_entries_inventory(data){
var grid = $$('grid_partner_products')
var values = {
opt: 'create',
values: data,
}
webix.ajax().sync().post('inventoryentries', values, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico'
msg_error(msg)
},
success:function(text, data, XmlHttpRequest){
var values = data.json();
if (values.ok) {
get_products()
$$('multi_invoices').setValue('products_home')
$$('lbl_partner').setValue('')
grid.clearAll()
}else{
msg_error(values.msg)
}
}
})
}
//~ Save add products
function cmd_save_products_add_click(id, e, node){
var grid = $$('grid_partner_products')
var count = 0
var products = []
var validate_import = false
var validate_cant = false
grid.eachRow(function(row){
var r = grid.getItem(row)
if(r.select){
var p = {}
count += 1
p.id_product = r.id_product
p.key = r.key
p.key_sat = r.key_sat1
p.description = r.description1
p.unit = r.unit
p.unit_value = r.unit_value1
p.cant = r.cant1
products.push(p)
if(p.unit_value < parseFloat(r.unit_value)){
validate_import = true
}
if(p.cant > r.cant){
validate_cant = true
}
}
})
if(!count){
msg = 'Selecciona al menos un registro'
msg_error(msg)
return
}
if(validate_import){
msg = 'El Valor Unitario no puede ser menor al Valor Unitario del proveedor'
msg_error(msg)
return
}
if(validate_cant){
msg = 'La Cantidad no puede ser mayor a la Cantidad del proveedor'
msg_error(msg)
return
}
var data = {
partner: cfg_products['partner'],
products: products,
}
msg = '¿Estás seguro de ingresar estos productos? <br/><br/>\
Esta acción no se puede deshacer.'
webix.confirm({
title: 'Agregar entrada',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
_add_entries_inventory(data)
}
}
})
}
//~ Import from xml
function cmd_add_products_from_xml_click(){
win_add_products_from_xml.init()
$$('win_add_products_from_xml').show()
}
//~ Upload XML
function cmd_upload_products_from_xml_click(){
var form = $$('form_upload_products_from_xml')
var values = form.getValues()
var list = $$('lst_up_products_from_xml')
var upload = $$('up_products_from_xml')
if(!list.count()){
$$('win_add_products_from_xml').close()
return
}
if(list.count() > 1){
msg = 'Selecciona solo un archivo'
msg_error(msg)
return
}
var template = upload.files.getItem(upload.files.getFirstId())
if(template.type.toLowerCase() != 'xml'){
msg = 'Archivo inválido.\n\nSe requiere un archivo XML'
msg_error(msg)
return
}
msg = '¿Estás seguro de importar este archivo? <br/><br/>\
Si hay datos previos seran reemplazados.'
webix.confirm({
title: 'Importar Productos',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
upload.send()
}
}
})
}
function up_products_from_xml_upload_complete(response){
if(response.status != 'server'){
msg = 'Ocurrio un error al subir el archivo'
msg_error(msg)
return
}
$$('win_add_products_from_xml').close()
if(response.error){
msg_error(response.error)
return
}
var grid = $$('grid_partner_products')
var data = response.data
cfg_products['partner'] = data.emisor
//~ cfg_products['xml'] = data.xml
var html = '<span class="webix_icon fa-user"></span><span class="lbl_partner">'
html += data.emisor.nombre + ' (' + data.emisor.rfc + ')</span>'
$$('lbl_partner').setValue(html)
grid.clearAll()
grid.parse(data.conceptos, 'json')
grid.refresh()
}
function get_partner_product(grid, row){
grid.refresh(row.id)
var partner_id = cfg_products['partner'].id
var filters = {
opt: 'product',
partner: cfg_products['partner'],
product_key: row.key,
}
if(!partner_id){
msg = 'El Proveedor no esta dado de alta'
msg_ok(msg)
return
}
webix.ajax().get('/partnerproducts', filters, {
error: function(text, data, xhr) {
msg_error('Ocurrio un error, consulta a soporte técnico.')
},
success: function(text, data, xhr){
var values = data.json()
if(values.ok){
row['id_product'] = values.row.id_product
row['key_sat1'] = values.row.key_sat1
row['description1'] = values.row.description1
row['unit_value1'] = values.row.unit_value1
grid.refresh(row.id)
}else{
msg_error(values.msg)
}
}
})
}
function grid_partner_products_select(row_id, state){
var grid = $$('grid_partner_products')
var row = grid.getItem(row_id)
if(state){
row['key_sat1'] = row.key_sat
row['description1'] = row.description
row['cant1'] = row.cant
row['unit_value1'] = 0.0
get_partner_product(grid, row)
}else{
row['key_sat1'] = ''
row['description1'] = ''
row['cant1'] = ''
grid.refresh(row_id)
}
}
function cmd_add_inventory_cancel_click(id, e, node){
$$('win_add_inventory').close()
}
function cmd_add_inventory_save_click(id, e, node){
var product_id = $$('txt_add_id').getValue()
//~ var product_key = $$('txt_add_key').getValue()
var new_cant = $$('txt_new_cant').getValue()
var warehouse = $$('lst_warehouses').getValue()
if(new_cant<=0) {
msg = 'La cantidad no puede ser cero'
msg_error(msg)
return
}
if($$('lst_warehouses').isVisible()){
if(!warehouse){
msg = 'Selecciona un almacen'
msg_error(msg)
return
}
}
msg = '¿Estas seguro de guardar esta entrada? <br/><br/>\
Esta acción no se puede deshacer'
webix.confirm({
title: 'Agregar entrada',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
add_product_stock(product_id, new_cant, warehouse)
}
}
})
}
function add_product_stock(product_id, new_cant, warehouse){
var data = {
product_id: product_id,
cant: new_cant,
warehouse: warehouse,
}
_add_entries_inventory_manual(product_id, data)
$$('win_add_inventory').close()
}
function _add_entries_inventory_manual(row_id, data){
var grid = $$('grid_products')
var values = {
opt: 'create_manual',
values: data,
}
webix.ajax().sync().post('inventoryentries', values, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico'
msg_error(msg)
},
success:function(text, data, XmlHttpRequest){
var values = data.json();
if (values.ok) {
grid.updateItem(row_id, values.row)
grid.refresh()
}else{
msg_error(values.msg)
}
}
})
}
function cmd_adjust_stock_click(id, e, node){
var id_product = $$('txt_id_product').getValue()
var row = $$('grid_warehouse_exists').getSelectedItem()
if (row == undefined){
msg_error('Selecciona un Almacen origen')
return
}
var warehouse_source = row.id
var cant_to_adjust = $$('txt_cant_to_adjust').getValue()
if(cant_to_adjust == 0){
msg_error('La cantidad a ajustar no puede ser cero')
return
}
if(cant_to_adjust > row.exists){
msg_error('La cantidad a ajustar no puede ser mayor a la existencia')
return
}
var values = {
id_product: id_product,
cant: cant_to_adjust,
storage: warehouse_source,
}
msg = '¿Estás seguro de hacer este ajuste?'
webix.confirm({
title: 'Ajuste de Almacen',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
_adjust_stock(values)
}
}
})
}
function _adjust_stock(args){
var grid = $$('grid_products')
var row = grid.getSelectedItem()
var values = {
opt: 'adjust_stock',
values: args,
}
webix.ajax().sync().post('warehouseproduct', values, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico'
msg_error(msg)
},
success:function(text, data, XmlHttpRequest){
var values = data.json();
if (values.ok) {
$$('txt_cant_to_adjust').setValue(0)
$$('grid_warehouse_exists').load('warehouseproduct?opt=by_product&id=' + args.id_product)
$$('grid_warehouse_exists').clearSelection()
grid.updateItem(row['id'], values.row)
grid.refresh()
msg_ok('Ajuste realizado correctamente')
}else{
msg_error(values.msg)
}
}
})
}

View File

@ -7,6 +7,7 @@ var last_forma_pago = ''
var tickets_controllers = {
init: function(){
$$('cmd_nuevo_ticket').attachEvent('onItemClick', cmd_nuevo_ticket_click)
$$('cmd_ticket_from_ticket').attachEvent('onItemClick', cmd_ticket_from_ticket_click)
$$('cmd_ticket_to_invoice').attachEvent('onItemClick', cmd_ticket_to_invoice_click)
$$('cmd_ticket_report_pdf').attachEvent('onItemClick', cmd_ticket_report_pdf_click)
$$('cmd_ticket_report_xls').attachEvent('onItemClick', cmd_ticket_report_xls_click)
@ -148,7 +149,9 @@ function configuracion_inicial_ticket_to_invoice(){
var grid = $$('grid_tickets_active')
var gridt = $$('grid_tickets_invoice')
var form = $$('form_ticket_invoice')
var chk = $$('chk_is_invoice_day')
chk.setValue(false)
get_active_tickets(grid)
form.setValues({id_partner: 0, lbl_tclient: 'Ninguno'})
gridt.attachEvent('onAfterAdd', function(id, index){
@ -183,6 +186,25 @@ function cmd_nuevo_ticket_click(){
}
function cmd_ticket_from_ticket_click(){
var grid = $$('grid_tickets')
if(grid.count() == 0){
return
}
var row = grid.getSelectedItem()
if (row == undefined){
msg_error('Selecciona un ticket')
return
}
configuracion_inicial_nuevo_ticket()
$$('multi_tickets').setValue('tickets_new')
$$('grid_tdetails').load('ticketsdetails?opt=by_ticket_id&id=' + row.id)
}
function cmd_ticket_to_invoice_click(){
configuracion_inicial_ticket_to_invoice()
$$('multi_tickets').setValue('tickets_invoice')
@ -342,22 +364,43 @@ function agregar_producto(values){
producto['valor_unitario'] = calcular_precio_con_impuestos(
parseFloat(producto['valor_unitario']), taxes)
producto['importe'] = producto['valor_unitario']
var id = grid.add(producto, 0)
edit_cant(id)
//~ var id = grid.add(producto, 0)
//~ edit_cant(id)
}else{
producto['cantidad'] = parseFloat(row.cantidad) + 1
producto['descuento'] = parseFloat(row.descuento)
producto['valor_unitario'] = parseFloat(row.valor_unitario)
precio_final = producto['valor_unitario'] - producto['descuento']
producto['importe'] = (precio_final * producto['cantidad']).round(DECIMALES)
grid.updateItem(row.id, producto)
//~ grid.updateItem(row.id, producto)
}
form.setValues({tsearch_product_key: '', tsearch_product_name: ''}, true)
//~ Validate stock
if(producto.inventario){
if(producto.cantidad > producto.existencia){
msg_error('No hay suficiente existencia de este producto')
return
}
}
if(row == undefined){
var id = grid.add(producto, 0)
edit_cant(id)
}else{
grid.updateItem(row.id, producto)
}
}
function buscar_producto_key(key){
webix.ajax().get('/values/productokey', {'key': key}, {
var filters = {
opt: 'by_key',
key: key,
}
webix.ajax().get('/products', filters, {
error: function(text, data, xhr) {
msg_error('Error al consultar')
},
@ -371,6 +414,20 @@ function buscar_producto_key(key){
}
}
})
//~ webix.ajax().get('/values/productokey', {'key': key}, {
//~ error: function(text, data, xhr) {
//~ msg_error('Error al consultar')
//~ },
//~ success: function(text, data, xhr){
//~ var values = data.json()
//~ if (values.ok){
//~ agregar_producto(values)
//~ } else {
//~ msg = 'No se encontró la clave<BR><BR>' + key
//~ msg_error(msg)
//~ }
//~ }
//~ })
}
@ -408,7 +465,29 @@ function grid_tickets_details_before_edit_stop(state, editor){
grid.editCancel()
grid.unblockEvent()
return true
}else if(cantidad <= 0){
msg = 'La cantidad no puede cero o menor'
msg_error(msg)
grid.blockEvent()
state.value = state.old
grid.editCancel()
grid.unblockEvent()
return true
}
//~ Validate stock
if(row['inventario']){
if(cantidad > row['existencia']){
msg = 'No hay suficiente existencia de este producto'
msg_error(msg)
grid.blockEvent()
state.value = state.old
grid.editCancel()
grid.unblockEvent()
return true
}
}
var valor_unitario = parseFloat(row['valor_unitario'])
var descuento = parseFloat(row['descuento'])
}
@ -423,6 +502,14 @@ function grid_tickets_details_before_edit_stop(state, editor){
grid.editCancel()
grid.unblockEvent()
return true
}else if(valor_unitario <= 0){
msg = 'El valor unitario no puede cero o menor'
msg_error(msg)
grid.blockEvent()
state.value = state.old
grid.editCancel()
grid.unblockEvent()
return true
}
var cantidad = parseFloat(row['cantidad'])
var descuento = parseFloat(row['descuento'])
@ -526,12 +613,18 @@ function cmd_cancelar_ticket_click(){
function chk_is_invoice_day_change(new_value, old_value){
var value = Boolean(new_value)
show('fs_ticket_search_client', !value)
enable('lst_global_periodicidad_2', value)
enable('lst_global_months_2', value)
var current_date = new Date()
var current_month = (current_date.getMonth() + 1).toString().padStart(2, '0')
$$('lst_global_months_2').setValue(current_month)
}
function send_timbrar_invoice(id){
//~ webix.ajax().get('/values/timbrar', {id: id, update: false}, function(text, data){
webix.ajax().post('invoices', {opt: 'timbrar', id: id, update: false}, function(text, data){
var values = data.json()
if(values.ok){
@ -559,6 +652,7 @@ function save_ticket_to_invoice(data){
if(values.ok){
msg_ok(values.msg)
send_timbrar_invoice(values.id)
$$('chk_is_invoice_day').setValue(false)
$$('multi_tickets').setValue('tickets_home')
}else{
msg_error(values.msg)
@ -595,12 +689,26 @@ function cmd_new_invoice_from_ticket_click(){
})
var data = new Object()
data['opt'] = 'invoice'
data['client'] = values.id_partner
data['tickets'] = tickets
data['is_invoice_day'] = chk.getValue()
data['opt'] = 'invoice'
msg = 'Todos los datos son correctos.<BR><BR>¿Estás seguro de generar esta factura?'
var periodicidad = ''
if(data['is_invoice_day']){
periodicidad = $$('lst_global_periodicidad_2').getValue() + '|'
periodicidad += $$('lst_global_months_2').getValue() + '|'
periodicidad += new Date().getFullYear()
}
data['periodicidad'] = periodicidad
msg = 'Todos los datos son correctos.<BR><BR>'
if(data['is_invoice_day']){
msg += 'Es Factura Global.<BR><BR>'
}
msg += '¿Estás seguro de generar esta factura?'
webix.confirm({
title: 'Generar Factura',
ok: 'Si',
@ -627,22 +735,30 @@ function grid_tickets_invoice_double_click(id, e, node){
function cmd_move_tickets_right_click(){
$$('grid_tickets_active').eachRow(
function(row){
this.copy(row, -1, $$('grid_tickets_invoice'))
}
)
$$('grid_tickets_active').clearAll()
var source = $$('grid_tickets_active')
var target = $$('grid_tickets_invoice')
_move_tickets(source, target)
}
function cmd_move_tickets_left_click(){
$$('grid_tickets_invoice').eachRow(
function(row){
this.copy(row, -1, $$('grid_tickets_active'))
}
)
$$('grid_tickets_invoice').clearAll()
var target = $$('grid_tickets_active')
var source = $$('grid_tickets_invoice')
_move_tickets(source, target)
}
function _move_tickets(source, target){
var rows = source.getSelectedItem()
if(rows == undefined){
source.eachRow(
function(row){
this.copy(row, -1, target)
}
)
source.clearAll()
}
}
@ -784,4 +900,4 @@ function grid_tdetails_render(data){
})
var id = $$('grid_ticket_total_up').getFirstId()
$$('grid_ticket_total_up').updateItem(id, {total: total})
}
}

View File

@ -1,10 +1,30 @@
var PUBLICO = "Público en general";
//~ Empresa Libre
//~ Copyright (C) 2016-2018 Mauricio Baeza Servin (web@correolibre.net)
//~
//~ This program is free software: you can redistribute it and/or modify
//~ it under the terms of the GNU General Public License as published by
//~ the Free Software Foundation, either version 3 of the License, or
//~ (at your option) any later version.
//~
//~ This program is distributed in the hope that it will be useful,
//~ but WITHOUT ANY WARRANTY; without even the implied warranty of
//~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//~ GNU General Public License for more details.
//~
//~ You should have received a copy of the GNU General Public License
//~ along with this program. If not, see <http://www.gnu.org/licenses/>.
var PUBLICO = "PUBLICO EN GENERAL";
var RFC_PUBLICO = "XAXX010101000";
var RFC_EXTRANJERO = "XEXX010101000";
var PAIS = "México";
var DECIMALES = 2;
//~ var DECIMALES_PU = 4;
var DECIMALES_TAX = 4;
var CLAVE_ANTICIPOS = '84111506';
var CURRENCY_MN = 'MXN';
var KEY_SAT_01 = '01010101';
var db = new loki('data.db');
@ -15,6 +35,7 @@ var table_totals = db.addCollection('totals', {unique: ['tax']})
var table_series = db.addCollection('series')
var table_usocfdi = db.addCollection('usocfdi')
var table_relaciones = db.addCollection('relaciones')
var table_waypayment = db.addCollection('waypayment')
var msg = ''
@ -34,11 +55,48 @@ var months = [
{id: 12, value: 'Diciembre'},
]
var days = [
{id: -1, value: '00'},
{id: 1, value: '01'},
{id: 2, value: '02'},
{id: 3, value: '03'},
{id: 4, value: '04'},
{id: 5, value: '05'},
{id: 6, value: '06'},
{id: 7, value: '07'},
{id: 8, value: '08'},
{id: 9, value: '09'},
{id: 10, value: '10'},
{id: 11, value: '11'},
{id: 12, value: '12'},
{id: 13, value: '13'},
{id: 14, value: '14'},
{id: 15, value: '15'},
{id: 16, value: '16'},
{id: 17, value: '17'},
{id: 18, value: '18'},
{id: 19, value: '19'},
{id: 20, value: '20'},
{id: 21, value: '21'},
{id: 22, value: '22'},
{id: 23, value: '23'},
{id: 24, value: '24'},
{id: 25, value: '25'},
{id: 26, value: '26'},
{id: 27, value: '27'},
{id: 28, value: '28'},
{id: 29, value: '29'},
{id: 30, value: '30'},
{id: 31, value: '31'},
]
function get_icon(tipo){
icons = {
xml: 'fa-file-code-o',
pdf: 'fa-file-pdf-o',
html: 'fa-html5',
zip: 'fa-file-zip-o',
email: 'fa-envelope-o',
print: 'fa-print',
@ -92,6 +150,11 @@ function show(nombre, value){
}
function show_column(table, column){
$$(table).showColumn(column)
}
function enable(nombre, value){
if(value == '0'){
value = false
@ -125,15 +188,65 @@ Number.prototype.round = function(decimals){
String.prototype.is_number = function(){
return /^\d+$/.test(this)
}
String.prototype.to_float = function(){
return get_float(this)
}
String.prototype.to_float4 = function(){
return get_float4(this)
}
function get_float(value){
return parseFloat(value.replace('$', '').replace(',', '').trim()).round(DECIMALES)
var f = parseFloat(value.replace('$', '').replace(/,/g, '').trim()).round(DECIMALES)
if(!f){
f = 0.00
}
return f
}
function get_float4(value){
var f = parseFloat(value.replace('$', '').replace(/,/g, '').trim()).round(DECIMALES_TAX)
if(!f){
f = 0.00
}
return f
}
var format_decimal_2 = webix.Number.numToStr({
groupSize: 3,
decimalSize: 2,
groupDelimiter: ",",
decimalDelimiter: "."
})
var format_decimal_4 = webix.Number.numToStr({
groupSize: 3,
decimalSize: 4,
groupDelimiter: ",",
decimalDelimiter: "."
})
function format_currency(value){
var fv = ''
if(get_config('decimales_precios') == 4){
fv = '$ ' + format_decimal_4(value)
}else{
fv = '$ ' + format_decimal_2(value)
}
return fv
}
function format_currency2(value){
return '$ ' + format_decimal_2(value)
}
function format_currency4(value){
return '$ ' + format_decimal_4(value)
}
@ -143,6 +256,7 @@ webix.protoUI({
$init:function(){
this.attachEvent("onItemClick", function(){
this.$setValue(this.config.raw, true)
this.getInputNode().select()
})
this.attachEvent("onBlur", function(){
this.$setValue(this.config.value)
@ -154,7 +268,57 @@ webix.protoUI({
$setValue:function(value, raw){
this.config.raw = value
if(!raw){
value = webix.i18n.priceFormat(value)
value = format_currency(value)
}
this.getInputNode().value = value
}
}, webix.ui.text)
webix.protoUI({
$cssName: "text",
name: "currency4",
$init:function(){
this.attachEvent("onItemClick", function(){
this.$setValue(this.config.raw, true)
this.getInputNode().select()
})
this.attachEvent("onBlur", function(){
this.$setValue(this.config.value)
})
},
$render:function(){
this.$setValue(this.config.value)
},
$setValue:function(value, raw){
this.config.raw = value
if(!raw){
value = format_currency4(value)
}
this.getInputNode().value = value
}
}, webix.ui.text)
webix.protoUI({
$cssName: "text",
name: "currency2",
$init:function(){
this.attachEvent("onItemClick", function(){
this.$setValue(this.config.raw, true)
this.getInputNode().select()
})
this.attachEvent("onBlur", function(){
this.$setValue(this.config.value)
})
},
$render:function(){
this.$setValue(this.config.value)
},
$setValue:function(value, raw){
this.config.raw = value
if(!raw){
value = format_currency2(value)
}
this.getInputNode().value = value
}
@ -210,6 +374,28 @@ webix.ui.datafilter.summTimbrada = webix.extend({
}, webix.ui.datafilter.summColumn);
webix.ui.datafilter.summTimbradaN = webix.extend({
refresh:function(master, node, value){
node.firstChild.innerHTML = this.summGenerate(master);
},
summGenerate:function(master){
var sum = 0
master.eachRow(function(id){
var row = master.getItem(id)
if(row.estatus == 'Timbrado'){
var importe = row.total
if(typeof importe === 'string'){
importe = row.total.to_float()
}
sum += importe
}
})
return webix.i18n.priceFormat(sum)
}
}, webix.ui.datafilter.summColumn);
function validate_rfc(value){
rfc = value.trim().toUpperCase();
if ( rfc == ""){
@ -380,6 +566,28 @@ function get_forma_pago(control){
}
function get_way_payment(){
webix.ajax().get('/satformapago', {opt: 'active_by_id'}, function(text, data){
var values = data.json()
table_waypayment.clear()
table_waypayment.insert(values)
})
}
function set_way_payment(control, filter99=false, current_way_payment=''){
if(filter99){
var values = table_waypayment.chain().find({'value': { '$ne' : 'Por definir' }}).data()
}else{
var values = table_waypayment.chain().data()
}
$$(control).getList().parse(values)
if(current_way_payment){
$$(control).setValue(current_way_payment)
}
}
function validate_regexp(value, pattern){
re = new RegExp(pattern, 'i');
if(value.match(re)){
@ -415,3 +623,74 @@ function pause(milliseconds) {
var dt = new Date();
while ((new Date()) - dt <= milliseconds) { /* Do nothing */ }
}
//~ Revisado
function lst_clear(lst){
lst.setValue('')
lst.define('options', [])
lst.refresh()
}
function lst_parse(lst, values){
lst.getList().parse(values)
}
function lst_parse2(lst_name, values){
obj = $$(lst_name)
obj.getList().parse(values)
}
function set_value(control, value){
obj = $$(control)
obj.blockEvent()
obj.setValue(value)
obj.unblockEvent()
}
function grid_parse(grid_name, values){
obj = $$(grid_name)
obj.clearAll()
obj.parse(values)
}
function activate_tab(parent, name){
$$(parent).getTabbar().setValue(name)
}
var opt_global_periodicidad = [
{id: '01', value: '[01] Diario'},
{id: '02', value: '[02] Semanal'},
{id: '03', value: '[03] Quincenal'},
{id: '04', value: '[04] Mensual'},
{id: '05', value: '[05] Bimestral'},
]
var opt_global_months = [
{id: '01', value: '[01] Enero'},
{id: '02', value: '[02] Febrero'},
{id: '03', value: '[03] Marzo'},
{id: '04', value: '[04] Abril'},
{id: '05', value: '[05] Mayo'},
{id: '06', value: '[06] Junio'},
{id: '07', value: '[07] Julio'},
{id: '08', value: '[08] Agosto'},
{id: '09', value: '[09] Septiembre'},
{id: '10', value: '[10] Octubre'},
{id: '11', value: '[11] Noviembre'},
{id: '12', value: '[12] Diciembre'},
{id: '13', value: '[13] Enero-Febrero'},
{id: '14', value: '[14] Marzo-Abril'},
{id: '15', value: '[15] Mayo-Junio'},
{id: '16', value: '[16] Julio-Agosto'},
{id: '17', value: '[17] Septiembre-Octubre'},
{id: '18', value: '[18] Noviembre-Diciembre'},
]

View File

@ -29,10 +29,6 @@ webix.i18n.locales["es-ES"] = {
today: "Hoy"
},
controls:{
select:"Seleccione",
invalidMessage: "Valor de entrada no válido"
},
dataExport:{
page:"Página",
of:"de"
@ -81,7 +77,12 @@ webix.i18n.locales["es-ES"] = {
italic: "Itálico"
},
combo:{
select:"Seleccionar",
selectAll:"Seleccionar todo",
unselectAll:"Deselecciona todo"
},
message:{
ok:"OK",
cancel:"Cancelar"
}
};

File diff suppressed because one or more lines are too long

View File

@ -1,275 +0,0 @@
webix.protoUI({
name: "sidebar",
defaults:{
titleHeight: 40,
type: "sideBar",
activeTitle: true,
select: true,
scroll: false,
collapsed: false,
collapsedWidth: 41,
position: "left",
width: 250,
mouseEventDelay: 10
},
$init: function(config){
this.$ready.push(this._initSidebar);
this.$ready.push(this._initContextMenu);
},
on_context:{},
on_mouse_move:{},
_initSidebar: function(){
this._fullWidth = this.config.width;
this.attachEvent("onBeforeOpen", function(id){
if(!this.config.multipleOpen)
this.closeAll();
return !this.config.collapsed;
});
this.attachEvent("onItemClick", function(id, ev, node){
if(this.getPopup() && !this.getPopup().config.hidden)
ev.showpopup = true;
if(webix.env.touch)
this._showPopup(id, node);
});
this.attachEvent("onBeforeSelect", function(id){
if(!this.getItem(id).$count){
var selected = this.getSelectedId();
if(selected && id!= selected){
var parentId = this.getParentId(selected);
this.removeCss(parentId, "webix_sidebar_selected");
}
return true;
}
return false;
});
this.attachEvent("onAfterSelect", function(id){
var parentId = this.getParentId(id);
this.addCss(parentId, "webix_sidebar_selected");
var title = this.getPopupTitle();
title.callEvent("onMasterSelect",[id]);
});
this.attachEvent("onMouseMove", function(id, ev, node){
this._showPopup(id, node);
});
if(this.config.collapsed)
this.collapse();
},
_showPopup: function(id, node){
if(this.config.collapsed){
var popup = this.getPopup();
if(popup){
var title = this.getPopupTitle();
if(title){
this._updateTitle(id);
}
var list = this.getPopupList();
if(list){
this._updateList(id);
}
var x = (this.config.position == "left"?this.config.collapsedWidth:-popup.config.width);
popup.show(node, {x: x , y:-1});
}
}
},
_updateTitle: function(id){
var title = this.getPopupTitle();
title.masterId = id;
title.parse(this.getItem(id));
var selectedId = this.getSelectedId();
if(selectedId && this.getParentId(selectedId) == id){
webix.html.addCss(title.$view, "webix_sidebar_selected", true);
}
else{
webix.html.removeCss(title.$view, "webix_sidebar_selected");
}
if(selectedId == id){
webix.html.addCss(title.$view, "webix_selected", true);
}
else{
webix.html.removeCss(title.$view, "webix_selected");
}
},
_updateList: function(id){
var list = this.getPopupList();
list.masterId = id;
var selectedId = this.getSelectedId();
var data = [].concat(webix.copy(this.data.getBranch(id)));
list.unselect();
if(data.length){
list.show();
list.data.importData(data);
if(list.exists(selectedId))
list.select(selectedId);
}
else
list.hide();
},
_initContextMenu: function(){
var config = this.config,
popup;
if(config.popup){
popup = webix.$$(config.popup);
}
if(!popup){
var dirClassName = (config.position=="left"?"webix_sidebar_popup_left":"webix_sidebar_popup_right");
var popupConfig = {
view:"popup",
css: "webix_sidebar_popup "+dirClassName,
autofit: false,
width: this._fullWidth - this.config.collapsedWidth,
borderless: true,
padding:0,
body:{
rows:[
{
view: "template", borderless: true, css: "webix_sidebar_popup_title",
template: "#value#", height: this.config.titleHeight+2,
on:{
onMasterSelect: function(id){
var master = this.getTopParentView().master;
if( master && master.getParentId(id) == this.masterId){
webix.html.addCss(this.$view, "webix_sidebar_selected", true);
}
if(master.config.collapsed && master.getItem(id).$level ==1){
webix.html.addCss(this.$view, "webix_selected", true);
}
}
},
onClick:{
webix_template: function(){
var id = this.masterId;
var master = this.getTopParentView().master;
if(!master.getItem(id).$count)
master.select(id);
}
}
},
{ view: "list", select: true, borderless: true, css: "webix_sidebar_popup_list", autoheight: true,
on:{
onAfterSelect: function(id){
this.getTopParentView().master.select(id);
}
}
}
]
}
};
webix.extend(popupConfig, config.popup||{}, true);
popup = webix.ui(popupConfig);
popup.master = this;
}
popup.attachEvent("onBeforeShow",function(){
return config.collapsed;
});
var master = this;
var h = webix.event(document.body,"mousemove", function(e){
var trg = e.target || e.srcElement;
if(!popup.config.hidden && !popup.$view.contains(trg) && !master.$view.firstChild.contains(trg)){
popup.hide();
}
});
this.attachEvent("onDestruct", function(){
if(webix.removeEvent)
webix.removeEvent(h);
if(popup)
popup.destructor();
});
config.popupId = popup.config.id;
},
getPopup: function(){
return webix.$$(this.config.popupId);
},
getPopupTitle: function(){
var popup = this.getPopup();
return popup.getBody().getChildViews()[0];
},
getPopupList: function(){
var popup = this.getPopup();
return popup.getBody().getChildViews()[1];
},
position_setter:function(value){
var newPos = value;
var oldPos = value=="left"?"right":"left";
webix.html.removeCss(this.$view, "webix_sidebar_"+oldPos);
webix.html.addCss(this.$view, "webix_sidebar_"+newPos, true);
var popup = this.getPopup();
if(popup){
var popupEl = popup.$view;
webix.html.removeCss(popupEl, "webix_sidebar_popup_"+oldPos);
webix.html.addCss(popupEl, "webix_sidebar_popup_"+newPos, true);
}
return value;
},
collapse: function(){
this.define("collapsed", true);
},
expand: function(){
this.define("collapsed", false);
},
toggle: function(){
var collapsed = !this.config.collapsed;
this.define("collapsed", collapsed);
},
collapsed_setter: function(value){
var width;
if(!value){
width = this._fullWidth;
}
else{
width = this.config.collapsedWidth;
this.closeAll();
}
if(!value){
this.type.collapsed = false;
webix.html.addCss(this.$view, "webix_sidebar_expanded", true);
}
else{
this.type.collapsed = true;
webix.html.removeCss(this.$view, "webix_sidebar_expanded");
}
this.define("width",width);
this.resize();
return value;
}
}, webix.ui.tree);
webix.type(webix.ui.tree, {
name:"sideBar",
height: "auto",
css: "webix_sidebar",
template: function(obj, common){
if(common.collapsed)
return common.icon(obj, common);
return common.arrow(obj, common)+common.icon(obj, common) +"<span>"+obj.value+"</span>";
},
arrow: function(obj, common){
var html = "";
var open = "";
for (var i=1; i<=obj.$level; i++){
if (i==obj.$level && obj.$count){
var className = "webix_sidebar_dir_icon webix_icon fa-angle-"+(obj.open?"down":"left");
html+="<span class='"+className+"'></span>";
}
}
return html;
},
icon:function(obj, common){
if(obj.icon)
return "<span class='webix_icon webix_sidebar_icon fa-"+obj.icon+"'></span>";
return "";
}
});

View File

@ -1,3 +1,18 @@
//~ Empresa Libre
//~ Copyright (C) 2016-2021 Mauricio Baeza Servin (public@correolibre.net)
//~
//~ This program is free software: you can redistribute it and/or modify
//~ it under the terms of the GNU General Public License as published by
//~ the Free Software Foundation, either version 3 of the License, or
//~ (at your option) any later version.
//~
//~ This program is distributed in the hope that it will be useful,
//~ but WITHOUT ANY WARRANTY; without even the implied warranty of
//~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//~ GNU General Public License for more details.
//~
//~ You should have received a copy of the GNU General Public License
//~ along with this program. If not, see <http://www.gnu.org/licenses/>.
var form_editar_usuario_elementos = [
@ -115,7 +130,7 @@ var admin_ui_niveles_educativos = {
var menu_data = [
{id: 'app_home', icon: 'dashboard', value: 'Inicio'},
{id: 'app_admin_home', icon: 'dashboard', value: 'Inicio'},
{id: 'app_emisor', icon: 'user-circle', value: 'Emisor'},
{id: 'app_folios', icon: 'sort-numeric-asc', value: 'Folios'},
{id: 'app_correo', icon: 'envelope-o', value: 'Correo'},
@ -131,8 +146,8 @@ var sidebar_admin = {
id: 'sidebar_admin',
data: menu_data,
ready: function(){
this.select('app_home');
this.open(this.getParentId('app_home'));
this.select('app_admin_home');
this.open(this.getParentId('app_admin_home'));
},
on:{
onAfterSelect: function(id){
@ -161,7 +176,9 @@ var emisor_datos_fiscales = [
invalidMessage: 'El C.P. es requerido'},
{view: 'text', id: 'emisor_cp2', name: 'emisor_cp2', width: 300,
label: 'C.P. de Expedición: ', attributes: {maxlength: 5}},
{}]},
{view: 'counter', id: 'emisor_hours', name: 'emisor_hours', value: 0,
required: false, label: 'Horas Dif.: ', step: 1, min: -1, max: 3}
]},
{cols: [
{view: 'label', label: 'Regimenes Fiscales *', required: true}, {}]},
{cols: [{view: 'list', id: 'lst_emisor_regimen', select: 'multiselect',
@ -189,7 +206,7 @@ var emisor_otros_datos= [
{template: 'Generales', type: 'section'},
{cols: [
{view: 'search', id: 'emisor_logo', icon: 'file-image-o',
name: 'emisor_logo', label: 'Logotipo: '},
name: 'emisor_logo', label: 'Logotipo: ', placeholder: 'Solo formato PNG'},
{view: 'text', id: 'emisor_nombre_comercial',
name: 'emisor_nombre_comercial', label: 'Nombre comercial: '},
]},
@ -223,33 +240,56 @@ var emisor_otros_datos= [
{cols: [{view: 'datepicker', id: 'ong_fecha_dof', name: 'ong_fecha_dof',
label: 'Fecha de DOF: ', disabled: true, format: '%d-%M-%Y',
placeholder: 'Fecha de publicación en el DOF'}, {}]},
{template: 'Timbrado y Soporte', type: 'section'},
{view: 'text', id: 'correo_timbrado',
name: 'correo_timbrado', label: 'Usuario para Timbrado: '},
{view: 'text', id: 'token_timbrado',
name: 'token_timbrado', label: 'Token de Timbrado: '},
{template: 'Soporte', type: 'section'},
//~ {view: 'text', id: 'correo_timbrado',
//~ name: 'correo_timbrado', label: 'Usuario para Timbrado: '},
//~ {view: 'text', id: 'token_timbrado',
//~ name: 'token_timbrado', label: 'Token de Timbrado: '},
{view: 'text', id: 'token_soporte',
name: 'token_soporte', label: 'Token para Respaldos: '},
name: 'token_soporte', label: 'Token de Soporte: '},
]
var emisor_certificado = [
var col_sello = {rows: [
{template: 'Certificado actual', type: 'section'},
{view: 'form', id: 'form_cert', rows: [
{cols: [{view: 'text', id: 'cert_rfc', name: 'cert_rfc',
label: 'RFC: ', readonly: true, placeholder: 'Ninguno'}, {}]},
label: 'RFC: ', readonly: true, placeholder: 'Ninguno'}]},
{cols: [{view: 'text', id: 'cert_serie', name: 'cert_serie',
label: 'Serie: ', readonly: true, placeholder: 'Ninguno'}, {}]},
label: 'Serie: ', readonly: true, placeholder: 'Ninguno'}]},
{cols: [{view: 'text', id: 'cert_desde', name: 'cert_desde',
label: 'Vigente desde: ', readonly: true}, {}]},
label: 'Vigente desde: ', readonly: true}]},
{cols: [{view: 'text', id: 'cert_hasta', name: 'cert_hasta',
label: 'Vigente hasta: ', readonly: true}, {}]},
]},
label: 'Vigente hasta: ', readonly: true}]},
]}
]}
var col_fiel = {rows: [
{template: 'Fiel actual', type: 'section'},
{view: 'form', id: 'form_fiel', rows: [
{cols: [{view: 'text', id: 'fiel_rfc', name: 'fiel_rfc',
label: 'RFC: ', readonly: true, placeholder: 'Ninguno'}]},
{cols: [{view: 'text', id: 'fiel_serie', name: 'fiel_serie',
label: 'Serie: ', readonly: true, placeholder: 'Ninguno'}]},
{cols: [{view: 'text', id: 'fiel_desde', name: 'fiel_desde',
label: 'Vigente desde: ', readonly: true}]},
{cols: [{view: 'text', id: 'fiel_hasta', name: 'fiel_hasta',
label: 'Vigente hasta: ', readonly: true}]},
]}
]}
//~ {view: 'uploader', id: 'up_cert', autosend: false, link: 'lst_cert',
//~ value: 'Seleccionar certificado', upload: '/values/files'}, {}]},
var emisor_certificado = [
{cols: [col_sello, col_fiel]},
{template: 'Cargar Certificado', type: 'section'},
{view: 'form', id: 'form_upload', rows: [
{cols: [{},
{view: 'uploader', id: 'up_cert', autosend: false, link: 'lst_cert',
value: 'Seleccionar certificado', upload: '/values/files'}, {}]},
value: 'Seleccionar certificado (CER y KEY)'}, {}]},
{cols: [{},
{view: 'list', id: 'lst_cert', name: 'certificado',
type: 'uploader', autoheight:true, borderless: true}, {}]},
@ -426,7 +466,10 @@ var emisor_folios = [
autowidth: true, type: 'form'},
{}]},
{template: 'Series guardadas', type: 'section'},
grid_folios
grid_folios,
{template: 'Opciones', type: 'section'},
{view: 'checkbox', id: 'chk_folio_custom', labelWidth: 0,
labelRight: 'Permitir capturar el folio manualmente (no recomendado): '},
]
@ -442,7 +485,9 @@ var emisor_correo = [
{}]},
{cols: [
{view: 'checkbox', id: 'correo_ssl', name: 'correo_ssl',
label: 'Usar TLS/SSL: '},
label: 'Usar TLS/SSL: ', maxWidth: 210},
{view: 'checkbox', id: 'correo_starttls', name: 'correo_starttls',
label: 'Usar STARTTLS: '},
{}]},
{cols: [
{view: 'text', id: 'correo_usuario', name: 'correo_usuario',
@ -476,9 +521,12 @@ var emisor_correo = [
{cols: [{},
{view: 'button', id: 'cmd_probar_correo', label: 'Probar Configuración',
autowidth: true, type: 'form'},
{maxWidth: 100},
{maxWidth: 50},
{view: 'button', id: 'cmd_guardar_correo', label: 'Guardar Configuración',
autowidth: true, type: 'form'},
{maxWidth: 50},
{view: 'button', id: 'cmd_clean_email', label: 'Borrar Configuración',
autowidth: true, type: 'form'},
{}]}
]
@ -544,39 +592,67 @@ var form_correo = {
}
var type_make_pdf = [
{id: 1, value: 'ODS'},
{id: 2, value: 'JSON'},
]
//~ Templates
var opt_templates_cfdi = [
{id: '_4.0.ods', value: 'CFDI v4.0'},
{id: '_4.0_cn_1.2.ods', value: 'CFDI v4.0 - Nómina v1.2'},
{id: '_4.0_cp_2.0.ods', value: 'CFDI v4.0 - Pagos v2.0'},
{id: '_4.0_ccp_2.0.ods', value: 'CFDI v4.0 - Carta Porte v2.0'},
{id: '_4.0_ccp_3.0.ods', value: 'CFDI v4.0 - Carta Porte v3.0'},
{id: '_4.0_cd_1.1.ods', value: 'CFDI v4.0 - Donativos v1.1'},
{id: '_4.0_cce_2.0.ods', value: 'CFDI v4.0 - Comercio Exterior v2.0'},
{id: '_4.0.json', value: 'CFDI v4.0 - JSON'},
{id: '_3.3.ods', value: 'CFDI v3.3'},
{id: '_3.3_cn_1.2.ods', value: 'CFDI v3.3 - Nómina v1.2'},
{id: '_3.3_ccp_2.0.ods', value: 'CFDI v3.3 - Carta Porte v2.0'},
{id: '_3.3_cp_1.0.ods', value: 'CFDI v3.3 - Pagos v1.0'},
{id: '_3.3.json', value: 'CFDI v3.3 - JSON'},
{id: '_3.2.ods', value: 'CFDI v3.2'}
]
var options_templates = [
{maxHeight: 15},
{cols: [{maxWidth: 15},
{view: 'search', id: 'txt_plantilla_factura_32', name: 'plantilla_factura_32',
label: 'Plantilla Factura v3.2 (ODS): ', labelPosition: 'top',
icon: 'file'}, {}]},
{maxHeight: 25},
{cols: [{maxWidth: 20},
{view: 'richselect', id: 'lst_templates_cfdi', label: 'Plantillas CFDI: ', labelWidth: 100, options: opt_templates_cfdi},
{maxWidth: 10},
{view: 'button', id: 'cmd_template_upload', type: 'iconButton', icon: 'file', width: 35},
{},
{maxWidth: 20} ]},
{maxHeight: 50},
{cols: [{maxWidth: 20},
{view: 'search', id: 'txt_plantilla_factura_html', name: 'plantilla_factura_html',
label: 'Plantilla Factura v3.3 (HTML): ', labelPosition: 'top',
icon: 'file'}, {maxWidth: 25},
{view: 'search', id: 'txt_plantilla_factura_css', name: 'plantilla_factura_css',
label: 'Archivo de estilos (CSS): ', labelPosition: 'top',
icon: 'file'}, {maxWidth: 20} ]},
{maxHeight: 20},
{cols: [{maxWidth: 15},
{view: 'search', id: 'txt_plantilla_factura_33', labelPosition: 'top',
label: 'Plantilla Factura v3.3 (ODS): ', icon: 'file'}, {}]},
{maxHeight: 20},
{cols: [{maxWidth: 15},
{view: 'search', id: 'txt_plantilla_factura_33j', name: 'plantilla_factura_33j',
label: 'Plantilla Factura v3.3 (JSON): ', labelPosition: 'top',
icon: 'file'}, {}]},
{maxHeight: 20},
{cols: [{maxWidth: 15},
{view: 'search', id: 'txt_plantilla_nomina1233', name: 'plantilla_nomina1233',
label: 'Plantilla Nomina v1.2 - Cfdi 3.3 (ODS): ', labelPosition: 'top',
icon: 'file'}, {}]},
{maxHeight: 20},
{cols: [{maxWidth: 15},
{cols: [{maxWidth: 20},
{view: 'search', id: 'txt_plantilla_ticket', name: 'plantilla_ticket',
label: 'Plantilla para Tickets (ODS): ', labelPosition: 'top',
icon: 'file'},
{view: 'search', id: 'txt_plantilla_donataria', name: 'plantilla_donataria',
label: 'Plantilla Donataria (solo ONGs): ', labelPosition: 'top',
icon: 'file'},
{}]},
{maxHeight: 20},
{cols: [{maxWidth: 20},
{view: 'radio', id: 'make_pdf_from', name: 'make_pdf_from', labelWidth: 150,
label: 'Generar PDF desde: ', value: 1, options: type_make_pdf},
{}]},
{}]
var options_pac = [
{id: 'finkok', value: 'Finkok'},
{id: 'comercio', value: 'Comercio Digital'},
]
var options_admin_otros = [
{maxHeight: 15},
{template: 'Facturación', type: 'section'},
@ -596,7 +672,7 @@ var options_admin_otros = [
{view: 'checkbox', id: 'chk_config_tax_locales', labelWidth: 0,
labelRight: 'Impuestos locales, calcular antes del descuento'},
{view: 'checkbox', id: 'chk_config_tax_decimals', labelWidth: 0,
labelRight: 'Calcular impuestos con 4 decimales'},
labelRight: 'Calcular impuestos con 4 decimales', hidden: true},
{view: 'checkbox', id: 'chk_config_price_with_taxes_in_invoice', labelWidth: 0,
labelRight: 'Precio incluye impuestos'},
{view: 'checkbox', id: 'chk_config_add_same_product', labelWidth: 0,
@ -605,34 +681,57 @@ var options_admin_otros = [
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_tax_locales_truncate', labelWidth: 0,
labelRight: 'Impuestos locales, truncar valores'},
{view: 'checkbox', id: 'chk_config_decimales_precios', labelWidth: 0,
labelRight: 'Precios con 4 decimales'},
{view: 'checkbox', id: 'chk_config_user_show_doc', labelWidth: 0,
labelRight: 'Usuarios pueden ver todos los documentos'},
]},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_invoice_by_ticket', labelWidth: 0,
labelRight: 'Factura global por ticket'},
{view: 'checkbox', id: 'chk_config_show_total_cant', labelWidth: 0,
labelRight: 'Mostrar total de cantidades'},
{view: 'checkbox', id: 'chk_config_show_filter_by_day', labelWidth: 0,
labelRight: 'Mostrar filtro por día'},
{}
]},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_cancel_invoices_by_admin', labelWidth: 0,
labelRight: 'Solo admins pueden cancelar'},
{}
]},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_change_date_invoice', labelWidth: 0,
labelRight: 'Permitir cambiar fecha al facturar [No recomendable]'},
{}
]},
{maxHeight: 15},
{template: 'Timbrado', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'richselect', id: 'lst_pac', name: 'lst_pac', width: 300,
label: 'PAC: ', value: '', required: true,
labelAlign: 'right', options: options_pac}, {view: 'label',
label: ' NO cambies este valor, a menos que se te haya indicado'},
]},
{cols: [{maxWidth: 15},
{view: 'text', id: 'user_timbrado', name: 'user_timbrado',
label: 'Usuario: ', labelAlign: 'right', required: true},
{view: 'text', id: 'token_timbrado', name: 'token_timbrado',
label: 'Token: ', labelAlign: 'right', required: true},
]},
{cols: [{maxWidth: 15}, {},
{view: 'button', id: 'cmd_save_pac', label: 'Guardar',
autowidth: true, type: 'form'}, {},
]},
{maxHeight: 20},
{template: 'Ayudas varias', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_anticipo', labelWidth: 0,
labelRight: 'Ayuda para generar anticipos'},
{}]},
{maxHeight: 20},
{template: 'Productos y Servicios', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_cuenta_predial', labelWidth: 0,
labelRight: 'Mostrar cuenta predial'},
{view: 'checkbox', id: 'chk_config_codigo_barras', labelWidth: 0,
labelRight: 'Mostrar código de barras'},
{view: 'checkbox', id: 'chk_config_precio_con_impuestos', labelWidth: 0,
labelRight: 'Mostrar precio con impuestos'},
{view: 'checkbox', id: 'chk_llevar_inventario', labelWidth: 0,
labelRight: 'Mostrar inventario'},
]},
{maxHeight: 20},
{template: 'Complementos', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_ine', labelWidth: 0,
labelRight: 'Usar el complemento INE'},
{view: 'checkbox', id: 'chk_config_edu', labelWidth: 0,
labelRight: 'Usar el complemento EDU'},
{}]},
{maxHeight: 20},
{template: 'Punto de venta', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_usar_punto_de_venta', labelWidth: 0,
@ -650,18 +749,198 @@ var options_admin_otros = [
labelRight: 'Solicitar cantidad al agregar'},
{view: 'checkbox', id: 'chk_ticket_total_up', labelWidth: 0,
labelRight: 'Mostrar total arriba'},
{}]},
{view: 'checkbox', id: 'chk_ticket_user_show_doc', labelWidth: 0,
labelRight: 'Usuarios pueden ver todos los documentos'}
]},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_cancel_tickets_by_admin', labelWidth: 0,
labelRight: 'Solo admins pueden cancelar'},
{}
]},
{maxHeight: 20},
{template: 'Nómina', type: 'section'},
{}]
var options_admin_partners = [
{maxHeight: 20},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_change_balance_partner',
labelWidth: 0, labelRight: 'Permitir cambiar saldo'},
]},
]
var grid_warehouse_cols = [
{id: 'id', header: 'ID', hidden: true},
{id: 'delete', header: '', width: 30, css: 'delete'},
{id: 'name', header: 'Nombre', fillspace: 1},
]
var grid_warehouse = {
view: 'datatable',
id: 'grid_warehouse',
select: 'row',
adjust: true,
headermenu: true,
footer: true,
columns: grid_warehouse_cols,
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.delete = '-'
})
}
},
}
var options_admin_products = [
{maxHeight: 20},
{cols: [{view: 'checkbox', id: 'chk_config_cuenta_predial', labelWidth: 15,
labelRight: 'Mostrar cuenta predial'}]},
{cols: [{view: 'checkbox', id: 'chk_config_codigo_barras', labelWidth: 15,
labelRight: 'Mostrar código de barras'}]},
{cols: [{view: 'checkbox', id: 'chk_config_precio_con_impuestos', labelWidth: 15,
labelRight: 'Mostrar precio con impuestos'}]},
{cols: [{view: 'checkbox', id: 'chk_llevar_inventario', labelWidth: 15,
labelRight: 'Mostrar inventario'}]},
{cols: [{maxWidth: 30}, {view: 'checkbox', id: 'chk_multi_stock', labelWidth: 15,
labelRight: 'Multialmacen', disabled: true}]},
{cols: [{maxWidth: 30}, {rows: [
{template: 'Agregar Almacen', type: 'section', id: 'template_add_warehouse'},
{cols: [
{view: 'text', id: 'txt_add_warehouse', label: 'Nombre: ',
labelPosition: 'left', required: true},
{view: 'button', id: 'cmd_add_warehouse', label: 'Agregar',
autowidth: true, type: 'iconButton', icon: 'plus'},
]},
{template: 'Almacenes', type: 'section'},
grid_warehouse,
]}, {},
]}
//~ {cols: [{view: 'checkbox', id: 'chk_use_packing', labelWidth: 15,
//~ labelRight: 'Usar empaques', hidden: true}]},
]
var options_admin_complements = [
{maxHeight: 10},
{template: 'Complemento de Nómina', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_usar_nomina', labelWidth: 0,
labelRight: 'Usar timbrado de Nómina'},
labelRight: 'Usar complemento de Nómina'},
{view: 'text', id: 'txt_config_nomina_serie', name: 'config_nomina_serie',
label: 'Serie', labelWidth: 50, labelAlign: 'right'},
{view: 'text', id: 'txt_config_nomina_folio', name: 'config_nomina_folio',
label: 'Folio', labelWidth: 50, labelAlign: 'right'},
{}]},
{}]
{maxWidth: 15}]},
{maxHeight: 10},
{template: 'Complemento de Pagos', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_pagos', labelWidth: 0,
labelRight: 'Usar complemento de pagos'},
{view: 'checkbox', id: 'chk_cfg_pays_data_bank', labelWidth: 0,
labelRight: 'Usar datos bancarios'},
{view: 'text', id: 'txt_config_cfdipay_serie', name: 'txt_config_cfdipay_serie',
label: 'Serie', labelWidth: 50, labelAlign: 'right'},
{view: 'text', id: 'txt_config_cfdipay_folio', name: 'txt_config_cfdipay_serie',
label: 'Folio', labelWidth: 50, labelAlign: 'right'},
{maxWidth: 15}]},
{maxHeight: 10},
{template: 'Complemento de Divisas', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_divisas', labelWidth: 0,
labelRight: 'Usar complemento de divisas'},
{maxWidth: 15}]},
{maxHeight: 10},
{template: 'Complemento INE', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_ine', labelWidth: 0,
labelRight: 'Usar el complemento INE'},
{maxWidth: 15}]},
{maxHeight: 10},
{template: 'Complemento para escuelas EDU', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_edu', labelWidth: 0,
labelRight: 'Usar el complemento EDU'},
{maxWidth: 15}]},
{maxHeight: 10},
{template: 'Complemento Leyendas Fiscales', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_leyendas_fiscales', labelWidth: 0,
labelRight: 'Usar el complemento Leyendas Fiscales'},
{view: 'button', id: 'cmd_admin_leyendas_fiscales', label: 'Leyendas Fiscales',
type: 'form', align: 'center', autowidth: true, disabled: true},
{}, {maxWidth: 15}
]},
{maxHeight: 10},
{template: 'Complemento para Carta Porte', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_carta_porte', labelWidth: 0,
labelRight: 'Usar el complemento Carta Porte'},
{maxWidth: 15}]},
{template: 'Complemento para Comercio Exterior', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_comercio_exterior', labelWidth: 0,
labelRight: 'Usar el complemento Comercio Exterior'},
{maxWidth: 15}]},
]
var controls_add_sucursal = [{cols: [
{maxWidth: 20},
{view: 'text', id: 'txt_sucursal_add_name', name: 'sucursal_add_name',
label: 'Nombre: ', labelPosition: 'top', required: true},
{view: 'richselect', id: 'lst_sucursal_add_invoice', name: 'sucursal_add_invoice',
label: 'Serie Facturas: ', labelPosition: 'top', required: true, options: []},
{view: 'text', id: 'txt_sucursal_add_ticket', name: 'sucursal_add_ticket',
required: true, label: 'Serie Tickets: ', labelPosition: 'top'},
{view: 'richselect', id: 'lst_sucursal_warehouse', name: 'sucursal_warehouse',
label: 'Almacen: ', labelPosition: 'top', required: false, options: [], hidden: true},
{view: 'button', id: 'cmd_add_sucursal', label: 'Agregar',
autowidth: true, type: 'iconButton', icon: 'plus'},
{maxWidth: 20},
]}]
var grid_sucursales_cols = [
{id: 'id', header: 'ID', hidden: true},
{id: 'delete', header: '', width: 30, css: 'delete'},
{id: 'name', header: 'Nombre', fillspace: 1},
{id: 'serie_invoice', header: 'Serie Facturas', fillspace: 1},
{id: 'serie_tickets', header: 'Serie Tickets', fillspace: 1},
{id: 'warehouse', header: 'Almacen', fillspace: 1, hidden: true},
]
var grid_sucursales = {
view: 'datatable',
id: 'grid_sucursales',
select: 'row',
adjust: true,
headermenu: false,
footer: true,
columns: grid_sucursales_cols,
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.delete = '-'
})
}
},
}
var options_admin_sucursales = [
{maxHeight: 10},
{template: 'Agregar Sucursal', type: 'section'},
{view: 'form', id: 'form_add_sucursal', rows: controls_add_sucursal},
{template: 'Sucursales', type: 'section'},
{cols: [{maxWidth: 10}, grid_sucursales, {maxWidth: 10}]},
{maxHeight: 20},
]
var tab_options = {
@ -671,26 +950,22 @@ var tab_options = {
cells: [
{header: 'Plantillas', body: {id: 'tab_admin_templates',
rows: options_templates}},
{header: 'Clientes y Proveedores', body: {id: 'tab_admin_partners',
view: 'scrollview', body: {rows: options_admin_partners}}},
{header: 'Productos y Servicios', body: {id: 'tab_admin_products',
view: 'scrollview', body: {rows: options_admin_products}}},
{header: 'Complementos', body: {id: 'tab_admin_complements',
view: 'scrollview', body: {rows: options_admin_complements}}},
{header: 'Otros', body: {id: 'tab_admin_otros', view: 'scrollview',
body: {rows: options_admin_otros}}},
]
{header: 'Sucursales', body: {id: 'tab_admin_sucursales', view: 'scrollview',
body: {rows: options_admin_sucursales}}},
],
}
var utilidades_archivos = [
{maxHeight: 15},
{template: 'Cargar Base de Datos de Factura Libre', type: 'section'},
{view: 'form', id: 'form_upload_bdfl', rows: [
{cols: [{},
{view: 'uploader', id: 'up_bdfl', autosend: false, link: 'lst_bdfl',
value: 'Seleccionar base de datos', upload: '/files/bdfl'}, {}]},
{cols: [{},
{view: 'list', id: 'lst_bdfl', name: 'bdfl',
type: 'uploader', autoheight: true, borderless: true}, {}]},
{cols: [{}, {view: 'button', id: 'cmd_subir_bdfl',
label: 'Subir base de datos de Factura Libre'}, {}]},
]},
{maxHeight: 15},
{maxHeight: 5},
{template: 'Importar archivo CFDI (XML)', type: 'section'},
{view: 'form', id: 'form_upload_cfdixml', rows: [
{cols: [{},
@ -743,7 +1018,9 @@ var grid_admin_monedas_cols = [
var grid_admin_bancos_cols = [
{id: 'id', header: 'ID', hidden: true},
{id: 'key', header: 'Clave', footer: {content: 'countRows', css: 'right'}},
{id: 'name', header: 'Nombre', adjust: 'data', footer: 'Bancos'},
{id: 'name', header: 'Nombre', footer: 'Bancos', fillspace: true},
{id: 'razon_social', header: 'Razón Social', fillspace: true},
{id: 'rfc', header: 'RFC', width: 125, editor: 'text'},
{id: 'activo', header: 'Activo', template: '{common.checkbox()}',
editor: 'checkbox'},
]
@ -790,7 +1067,7 @@ var grid_admin_bancos = {
id: 'grid_admin_bancos',
select: 'cell',
adjust: true,
autowidth: true,
editable: true,
headermenu: true,
footer: true,
columns: grid_admin_bancos_cols,
@ -857,6 +1134,19 @@ var grid_admin_usos_cfdi_cols = [
]
var grid_admin_regimenes_fiscales_cols = [
{id: 'id', header: 'ID', hidden: true},
{id: 'key', header: 'Clave', adjust: 'header'},
{id: 'name', header: 'Nombre', width: 500},
{id: 'fisica', header: 'Físicas', adjust: 'header',
template: format_bool_fisica},
{id: 'moral', header: 'Morales', adjust: 'header',
template: format_bool_moral},
{id: 'activo', header: 'Activa', template: '{common.checkbox()}',
editor: 'checkbox', adjust: 'header'},
]
var grid_admin_formasdepago = {
view: 'datatable',
id: 'grid_admin_formasdepago',
@ -869,6 +1159,18 @@ var grid_admin_formasdepago = {
}
var grid_admin_regimenes_fiscales = {
view: 'datatable',
id: 'grid_admin_regimenes_fiscales',
select: 'cell',
adjust: true,
autowidth: true,
headermenu: true,
footer: true,
columns: grid_admin_regimenes_fiscales_cols,
}
var grid_admin_usos_cfdi = {
view: 'datatable',
id: 'grid_admin_usos_cfdi',
@ -891,6 +1193,7 @@ var admin_taxes = [
'CEDULAR',
'CMIC',
'SUPERVISION',
'MANO DE OBRA',
]
var admin_sat_impuestos = {cols: [{maxWidth: 15},
@ -966,7 +1269,7 @@ var sat_bancos = [
{maxHeight: 20},
{cols: [{maxWidth: 15}, {view: 'label', label: msg_bancos}, {}]},
{maxHeight: 20},
{cols: [{maxWidth: 15}, grid_admin_bancos, {}]},
{cols: [{maxWidth: 15}, grid_admin_bancos]},
{maxHeight: 20},
]
@ -1039,6 +1342,101 @@ var sat_usos_cfdi = [
]
var msg_regimenes_fiscales = 'Administrar Regimenes Fiscales.'
var sat_regimenes_fiscales = [
{maxHeight: 20},
{cols: [{maxWidth: 15}, {view: 'label', label: msg_regimenes_fiscales}, {}]},
{maxHeight: 20},
{cols: [{maxWidth: 15}, grid_admin_regimenes_fiscales, {}]},
{maxHeight: 20},
]
var suggest_sat_unidades_peso = {
view: 'gridsuggest',
id: 'grid_unidadpeso_found',
name: 'grid_unidadpeso_found',
body: {
autoConfig: false,
scroll:true,
autoheight:false,
header: true,
yCount: 10,
columns: [
{id: 'id', hidden: true},
{id: 'key', adjust: 'data', header: 'Clave'},
{id: 'name', adjust: 'data', header: 'Unidad'},
],
dataFeed:function(text){
if (text.length > 1){
this.load('/values/satunidadespeso?key=' + text)
}else{
this.hide()
}
}
},
}
var buscar_carta_unidades_peso = {
view: 'search',
id: 'buscar_carta_unidades_peso',
label: 'Buscar Unidad de Peso en el catálogo del SAT',
labelPosition: 'top',
suggest: suggest_sat_unidades_peso,
placeholder: 'Por clave o descripción. Captura al menos tres letras',
}
var columns_carta_unidades_peso = [
{id: 'id', header: 'ID', hidden: true},
{id: 'delete', header: '', width: 30, css: 'delete'},
{id: 'key', header: 'Clave'},
{id: 'name', header: 'Nombre', adjust: 'data'},
{id: 'activo', header: 'Activo', template: '{common.checkbox()}',
editor: 'checkbox'},
]
var grid_carta_unidades_peso = {
view: 'datatable',
id: 'grid_carta_unidades_peso',
url: 'satunidadespeso?opt=all',
select: 'cell',
adjust: true,
autowidth: true,
headermenu: true,
columns: columns_carta_unidades_peso,
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.delete = '-'
})
}
},
}
var carta_porte_unidades_peso = [
{maxHeight: 20},
{cols: [{maxWidth: 15}, buscar_carta_unidades_peso, {}]},
{maxHeight: 20},
{cols: [{maxWidth: 15}, grid_carta_unidades_peso, {}]},
{maxHeight: 20},
]
var tab_sat_carta_porte = [{
view: 'tabview',
id: 'tab_sat_carta_porte',
multiview: true,
animate: true,
cells: [
{id: 'Unidades de Peso', rows: carta_porte_unidades_peso},
]
}]
var tab_sat = {
view: 'tabview',
id: 'tab_sat',
@ -1051,6 +1449,8 @@ var tab_sat = {
{id: 'Unidades', rows: sat_unidades},
{id: 'Formas de Pago', rows: sat_formasdepago},
{id: 'Usos de CFDI', rows: sat_usos_cfdi},
{id: 'Regimenes Fiscales', rows: sat_regimenes_fiscales},
{id: 'Carta Porte', rows: tab_sat_carta_porte},
],
}
@ -1082,12 +1482,14 @@ var grid_usuarios_cols = [
hidden: true},
{id: 'ultimo_ingreso', header: 'Ultimo Ingreso', fillspace: 1,
hidden: true},
{id: 'in_branch', header: 'En Sucursal', template: '{common.checkbox()}',
editor: 'checkbox', adjust: 'header', hidden: true},
{id: 'es_activo', header: 'Activo', template: '{common.checkbox()}',
editor: 'checkbox', adjust: 'header'},
{id: 'es_admin', header: 'Es Admin', template: '{common.checkbox()}',
editor: 'checkbox', adjust: 'header'},
{id: 'es_superusuario', header: 'Es SU', template: '{common.checkbox()}',
editor: 'checkbox', adjust: 'header'},
editor: 'checkbox', adjust: 'header', hidden: true},
]
@ -1096,7 +1498,7 @@ var grid_usuarios = {
id: 'grid_usuarios',
select: 'row',
adjust: true,
headermenu: true,
headermenu: false,
footer: true,
columns: grid_usuarios_cols,
on:{
@ -1116,6 +1518,10 @@ var usuarios_admin = [
{maxHeight: 20},
{template: 'Usuarios Registrados', type: 'section'},
{cols: [{maxWidth: 10}, grid_usuarios, {maxWidth: 10}]},
{maxHeight: 20},
{template: 'Opciones', type: 'section'},
{cols: [{view: 'checkbox', id: 'chk_users_notify_access', labelWidth: 15,
labelRight: 'Notificar accesos al sistema (solo a administradores)'}]},
{},
]
@ -1280,3 +1686,105 @@ var body_win_emisor_logo = [
var grid_cols_admin_leyendas_fiscales = [
{id: 'id', header: 'ID', hidden: true},
{id: 'delete', header: '', width: 30, css: 'delete'},
{id: 'texto_leyenda', header: 'Leyenda', fillspace: 1},
{id: 'norma', header: 'Norma', fillspace: 1},
{id: 'disposicion_fiscal', header: 'Disposición Fiscal', fillspace: 1},
//~ {id: 'active', header: 'Activa', template: '{common.checkbox()}',
//~ editor: 'checkbox'},
]
var grid_admin_leyendas_fiscales = {
view: 'datatable',
id: 'grid_admin_leyendas_fiscales',
select: 'row',
adjust: true,
autoheight: true,
headermenu: true,
columns: grid_cols_admin_leyendas_fiscales,
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.delete = '-'
})
}
},
}
var form_controls_admin_leyendas_fiscales = [
{cols: [
{view: 'text', id: 'txt_texto_leyenda', label: 'Leyenda', width: 200,
labelPosition: 'top', name: 'texto_leyenda', required: true},
{view: "text", id: 'txt_norma_fiscal', label: 'Norma', width: 200,
name: 'norma', labelPosition: 'top'},
{view: "text", id: 'txt_disposicion_fiscal', label: 'Disposición',
name: 'disposicion_fiscal', labelPosition: 'top', width: 200}
]},
{cols: [{},
{view: 'button', type: 'form', icon: 'plus', label: 'Agregar', autowidth: true,
click: function(){add_admin_leyenda_fiscal_click()}
}, {}]},
grid_admin_leyendas_fiscales,
{},
{cols:[{},
{view: 'button', value: 'Cerrar', click: "$$('win_leyendas_fiscales').close()"},
{}]}
]
var admin_ui_leyendas_fiscales = {
init: function(){
webix.ui({
view: 'window',
id: 'win_leyendas_fiscales',
head: 'Leyendas Fiscales',
width: 800,
modal: true,
position: 'center',
body: {
view: 'form', id: 'form_admin_leyendas_fiscales',
elements: form_controls_admin_leyendas_fiscales
}
})
$$('grid_admin_leyendas_fiscales').attachEvent('onItemClick', grid_admin_leyendas_fiscales_click)
},
}
var body_set_branch_user = {rows: [{minHeight: 10},
{view: 'text', id: 'txt_user_id', readonly: true, hidden: true},
//~ {view: 'text', id: 'txt_user_name', label: 'Usuario', readonly: true},
{view: 'richselect', id: 'lst_branchs', name: 'lst_branchs',
label: 'Sucursales: ', required: true, options: []},
{minHeight: 10},
{cols: [{},
{view: 'button', id: 'cmd_set_branch_user_save', label: 'Guardar'}, {},
{view: 'button', id: 'cmd_set_branch_user_cancel', label: 'Cancelar', type: 'danger'}, {}
]},
{minHeight: 20},
]}
var win_set_branch_user = {
init: function(){
webix.ui({
view: 'window',
id: 'win_set_branch_user',
width: 400,
modal: true,
position: 'center',
head: 'Asignar Sucursal',
body: body_set_branch_user,
})
$$('cmd_set_branch_user_save').attachEvent('onItemClick', cmd_set_branch_user_save_click)
$$('cmd_set_branch_user_cancel').attachEvent('onItemClick', cmd_set_branch_user_cancel_click)
}
}

View File

@ -1,10 +1,25 @@
//~ Empresa Libre
//~ Copyright (C) 2016-2018 Mauricio Baeza Servin (web@correolibre.net)
//~
//~ This program is free software: you can redistribute it and/or modify
//~ it under the terms of the GNU General Public License as published by
//~ the Free Software Foundation, either version 3 of the License, or
//~ (at your option) any later version.
//~
//~ This program is distributed in the hope that it will be useful,
//~ but WITHOUT ANY WARRANTY; without even the implied warranty of
//~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//~ GNU General Public License for more details.
//~
//~ You should have received a copy of the GNU General Public License
//~ along with this program. If not, see <http://www.gnu.org/licenses/>.
var toolbar_banco = [
{view: 'richselect', id: 'lst_cuentas_banco', label: 'Cuenta',
labelWidth: 100, options: []},
{view: 'text', id: 'txt_cuenta_moneda', label: 'Moneda', readonly: true},
{view: 'currency', id: 'txt_cuenta_saldo', label: 'Saldo', readonly: true,
{view: 'currency2', id: 'txt_cuenta_saldo', label: 'Saldo', readonly: true,
inputAlign: 'right', value: 0}
]
@ -26,6 +41,11 @@ var toolbar_movimientos_banco = [
{view: 'button', id: 'cmd_agregar_deposito', label: 'Depósito',
type: 'iconButton', autowidth: true, icon: 'plus'},
{},
{view: 'button', id: 'cmd_complemento_pago', label: 'Generar Factura de Pago',
type: 'iconButton', autowidth: true, icon: 'file-code-o'},
{view: 'button', id: 'cmd_show_invoice_pay', label: 'Ver Facturas de Pago',
type: 'iconButton', autowidth: true, icon: 'table'},
{},
{view: 'button', id: 'cmd_cancelar_movimiento', label: 'Cancelar',
type: 'iconButton', autowidth: true, icon: 'ban'},
]
@ -35,6 +55,7 @@ var grid_cuentabanco_cols = [
{id: 'id', header:'ID', hidden: true},
{id: 'fecha', header: 'Fecha', width: 150},
{id: 'numero_operacion', header: 'Referencia'},
{id: 'way_payment', header: 'Forma de Pago', hidden: true},
{id: 'descripcion', header: ['Descripción', {content: 'textFilter'}],
fillspace:true},
{id: 'retiro', header: ['Retiro', {content: 'numberFilter'}],
@ -43,6 +64,7 @@ var grid_cuentabanco_cols = [
width: 125, format: webix.i18n.priceFormat, css: 'right'},
{id: 'saldo', header: ['Saldo'],
width: 125, format: webix.i18n.priceFormat, css: 'right'},
{id: 'invoice', header: ['FP'], width: 40, css: 'center', hidden: true},
]
@ -62,7 +84,7 @@ var grid_cfdi_por_pagar_cols = [
{id: 'index', header: '#', adjust: 'data', css: 'right'},
{id: 'id', header: 'ID', hidden: true},
{id: 'serie', header: 'Serie', adjust: 'data'},
{id: 'folio', header: 'Folio', adjust: 'data', css: 'right'},
{id: 'folio', header: ['Folio', {content: 'numberFilter'}], adjust: 'data', css: 'right'},
{id: 'uuid', header: 'UUID', width: 250, hidden: true},
{id: 'fecha', header: 'Fecha y Hora', width: 150, sort: 'date'},
{id: 'tipo_comprobante', header: 'Tipo', adjust: 'data'},
@ -70,6 +92,10 @@ var grid_cfdi_por_pagar_cols = [
{id: 'cliente', header: ['Razón Social', {content: 'selectFilter'}],
fillspace:true, sort: 'string'},
{id: 'total', header: ['Total'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right', hidden: true},
{id: 'currency', header: ['Moneda', {content: 'selectFilter'}],
adjust: 'data', sort: 'string', hidden: true},
{id: 'total_mn', header: ['Total M.N'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
{id: 'saldo', header: ['Saldo'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
@ -87,11 +113,62 @@ var grid_cfdi_este_deposito_cols = [
{id: 'estatus', header: 'Estatus', adjust: 'header'},
{id: 'cliente', header: ['Razón Social'], fillspace: true},
{id: 'total', header: ['Total'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right', hidden: true},
{id: 'currency', header: ['Moneda', {content: 'selectFilter'}],
adjust: 'data', sort: 'string', hidden: true},
{id: 'total_mn', header: ['Total M.N'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
{id: 'saldo', header: ['Saldo'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
{id: 'this_pay', header: ['Este pago'], width: 125, sort: 'int', hidden: true,
format: webix.i18n.priceFormat, css: 'right', editor: 'text'},
{id: 'importe', header: ['Este pago'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right', editor: 'text'},
{id: 'type_change', header: ['T.C.'], width: 75, hidden: true,
format: format_currency4, css: 'right'},
]
var grid_cfdi_pay_cols = [
{id: 'index', header: '#', adjust: 'data', css: 'right',
footer: {content: 'countRows', colspan: 3, css: 'right'}},
{id: "id", header:"ID", hidden:true},
{id: 'serie', header: ["Serie"], adjust: "data", sort: 'string'},
{id: 'folio', header: ['Folio'], adjust: 'data',
sort: 'int', css: 'right', footer: {text: 'Facturas', colspan: 3}},
{id: "uuid", header: ["UUID"], adjust: "data",
sort:"string", hidden:true},
{id: "fecha", header: ["Fecha y Hora"],
adjust: "data", sort: "string"},
{id: "tipo_comprobante", header: ["Tipo"],
adjust: 'header', sort: 'string'},
{id: "estatus", header: ["Estatus"],
adjust: "data", sort:"string"},
{id: 'cliente', header: ['Razón Social'], fillspace: true},
{id: 'xml', header: 'XML', adjust: 'data', template: get_icon('xml')},
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
{id: 'email', header: '@', adjust: 'data', template: get_icon('email')}
]
var grid_pay_related_cols = [
{id: 'index', header: '#', adjust: 'data', css: 'right'},
{id: 'id', header: 'ID', hidden: true},
{id: 'serie', header: 'Serie', adjust: 'data'},
{id: 'folio', header: 'Folio', adjust: 'data', css: 'right'},
{id: 'uuid', header: 'UUID', width: 250, hidden: true},
{id: 'fecha', header: 'Fecha y Hora', width: 150, sort: 'date'},
{id: 'tipo_comprobante', header: 'Tipo', adjust: 'data'},
{id: 'estatus', header: 'Estatus', adjust: 'header'},
{id: 'cliente', header: ['Razón Social'], fillspace: true},
{id: 'total', header: ['Total'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
{id: 'saldo', header: ['Saldo'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right', css: 'right',
footer: 'Importe Depósito'},
{id: 'importe', header: ['Este pago'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right',
footer: {content: 'summColumn', css: 'right'}},
]
@ -121,6 +198,7 @@ var grid_cfdi_este_deposito = {
view: 'datatable',
id: 'grid_cfdi_este_deposito',
select: 'row',
multiselect: true,
autoConfig: false,
adjust: true,
height: 200,
@ -139,9 +217,111 @@ var grid_cfdi_este_deposito = {
}
var grid_cfdi_pay = {
view: 'datatable',
id: 'grid_cfdi_pay',
select: 'row',
autoConfig: false,
adjust: true,
autoheight: true,
resizeColumn: true,
headermenu: true,
columns: grid_cfdi_pay_cols,
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.index = i + 1
})
}
},
}
var grid_pay_related = {
view: 'datatable',
id: 'grid_pay_related',
select: 'row',
autoConfig: false,
adjust: true,
autoheight: true,
resizeColumn: true,
headermenu: true,
footer: true,
columns: grid_pay_related_cols,
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.index = i + 1
})
}
},
}
var grid_bank_invoice_pay_cols = [
{id: 'index', header: '#', adjust: 'data', css: 'right',
footer: {content: 'countRows', colspan: 3, css: 'right'}},
{id: "id", header:"ID", hidden:true},
{id: 'serie', header: ["Serie"], adjust: "data", sort: 'string',
template: '{common.subrow()} #serie#'},
{id: 'folio', header: ['Folio', {content: 'numberFilter'}], adjust: 'header',
sort: 'int', css: 'right', footer: {text: 'Facturas', colspan: 3}},
{id: "uuid", header: ["UUID", {content: "textFilter"}], adjust: "data",
sort:"string", hidden:true},
{id: "fecha", header: ["Fecha y Hora"], width: 135,
sort: "string"},
{id: "tipo_comprobante", header: ["Tipo"], adjust: 'data',
sort: 'string'},
{id: "estatus", header: ["Estatus", {content: "selectFilter"}],
adjust: "header", sort:"string"},
{id: 'movimiento', header: ['Movimiento', {content: "selectFilter"}],
adjust: 'data', sort: 'string'},
{id: 'total', header: ['Total', {content: 'numberFilter'}],
width: 125, sort: 'int', format: webix.i18n.priceFormat, css: 'right',
hidden: true},
{id: 'currency', header: ['Moneda', {content: 'selectFilter'}],
adjust: 'data', sort: 'string', hidden: true},
{id: 'total_mn', header: ['Total M.N.', {content: 'numberFilter'}],
width: 150, sort: 'int', format: webix.i18n.priceFormat, css: 'right',
footer: {content: 'summTimbrada', css: 'right'}},
{id: 'cliente', header: ['Razón Social', {content: 'selectFilter'}],
fillspace: true, sort: 'string'},
{id: 'xml', header: 'XML', adjust: 'data', template: get_icon('xml')},
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
//~ {id: 'ods', header: 'ODS', adjust: 'data', template: get_icon('table')},
//~ {id: 'zip', header: 'ZIP', adjust: 'data', template: get_icon('zip')},
{id: 'email', header: '@', adjust: 'data', template: get_icon('email')}
]
var grid_bank_invoice_pay = {
view: 'datatable',
id: 'grid_bank_invoice_pay',
select: 'row',
adjust: true,
footer: true,
resizeColumn: true,
headermenu: true,
columns: grid_bank_invoice_pay_cols,
scheme:{
$change:function(item){
if (item.estatus == 'Cancelada'){
item.$css = 'cancel'
}
}
},
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.index = i + 1
})
}
},
}
var toolbar_banco_retiro = [
{view: 'label', label: 'Agregar retiro de banco'},
{},
{view: 'label', label: 'Agregar retiro de banco', id: 'title_bank_retiro'},
{view: 'button', id: 'cmd_guardar_retiro', label: 'Guardar Retiro',
type: 'iconButton', autowidth: true, icon: 'minus'},
{view: 'icon', click: '$$("multi_bancos").setValue("banco_home")',
@ -150,8 +330,7 @@ var toolbar_banco_retiro = [
var toolbar_banco_deposito = [
{view: 'label', label: 'Agregar depósito de banco'},
{},
{view: 'label', label: 'Agregar depósito de banco', id: 'title_bank_deposit'},
{view: 'button', id: 'cmd_guardar_deposito', label: 'Guardar Depósito',
type: 'iconButton', autowidth: true, icon: 'plus'},
{view: 'icon', click: '$$("multi_bancos").setValue("banco_home")',
@ -159,6 +338,46 @@ var toolbar_banco_deposito = [
]
var toolbar_bank_pay = [
{view: 'label', label: 'Factura de pago'},
{},
{view: 'button', id: 'cmd_pay_stamp', label: 'Timbrar',
type: 'iconButton', autowidth: true, icon: 'ticket'},
{view: 'button', id: 'cmd_pay_cancel', label: 'Cancelar',
type: 'iconButton', autowidth: true, icon: 'minus'},
{view: 'button', id: 'cmd_pay_delete', label: 'Eliminar',
type: 'iconButton', autowidth: true, icon: 'ban'},
{view: 'checkbox', id: 'chk_pay_close_when_stamp',
label: 'Cerrar al timbrar', tooltip: 'Cerrar al timbrar'},
{},
{view: 'icon', click: '$$("multi_bancos").setValue("banco_home")',
icon: 'times-circle'}
]
var toolbar_bank_invoice_pay = [
{view: 'label', label: 'Administración de Facturas de Pago'},
{},
{view: 'icon', click: '$$("multi_bancos").setValue("banco_home")',
icon: 'times-circle'}
]
var toolbar_bank_invoice_pay_filter = [
{view: 'richselect', id: 'filter_invoice_pay_year', label: 'Año',
labelAlign: 'right', labelWidth: 50, width: 150, options: []},
{view: 'richselect', id: 'filter_invoice_pay_month', label: 'Mes',
labelAlign: 'right', labelWidth: 50, width: 175, options: months},
{view: 'daterangepicker', id: 'filter_invoice_pay_dates', label: 'Fechas',
labelAlign: 'right', width: 275},
{view: 'button', id: 'cmd_invoice_pay_sat', label: 'SAT',
type: 'iconButton', autowidth: true, icon: 'check-circle'},
{view: 'button', id: 'cmd_invoice_pay_cancel', label: 'Cancelar',
type: 'iconButton', autowidth: true, icon: 'ban'},
{},
]
var controls_banco_retiro = [
{view: 'toolbar', elements: toolbar_banco_retiro},
{cols: [
@ -177,7 +396,7 @@ var controls_banco_retiro = [
{view: 'richselect', id: 'lst_retiro_forma_pago',
name: 'retiro_forma_pago', label: 'Forma de Pago', required: true,
options: [], labelWidth: 125, labelAlign: 'right'},
{view: 'currency', type: 'text', id: 'txt_retiro_importe',
{view: 'currency2', type: 'text', id: 'txt_retiro_importe',
name: 'retiro_importe', label: 'Importe', labelAlign: 'right',
required: true, invalidMessage: 'Captura un valor númerico',
inputAlign: 'right', value: ''}
@ -208,10 +427,14 @@ var controls_banco_deposito = [
{view: 'richselect', id: 'lst_deposito_forma_pago',
name: 'deposito_forma_pago', label: 'Forma de Pago', required: true,
options: [], labelWidth: 125, labelAlign: 'right'},
{view: 'currency', type: 'text', id: 'txt_deposito_importe',
{view: 'currency2', type: 'text', id: 'txt_deposito_importe',
name: 'deposito_importe', label: 'Importe', labelAlign: 'right',
required: true, invalidMessage: 'Captura un valor númerico',
inputAlign: 'right', value: ''}
inputAlign: 'right', value: ''},
{view: 'currency4', type: 'text', id: 'deposit_type_change',
name: 'deposit_type_change', label: 'T.C.', labelAlign: 'right',
required: false, invalidMessage: 'Captura un valor númerico',
inputAlign: 'right', value: '1.0000', width: 175, hidden: true}
]},
{cols: [
{view: 'textarea', id: 'deposito_descripcion', label: 'Descripción',
@ -220,8 +443,13 @@ var controls_banco_deposito = [
]},
{cols: [
{view: 'label', label: '<b>Facturas por pagar: </b>'},
{view: 'button', id: 'cmd_invoice_payed', label: 'Pagada directamente',
type: 'iconButton', autowidth: true, icon: 'check-circle'},
{view: 'richselect', id: 'lst_partner_account_bank', hidden: true,
name: 'partner_account_bank', label: 'Cuenta Origen', required: false,
options: [], labelWidth: 125, labelAlign: 'right'},
{},
{view: 'button', id: 'cmd_invoice_payed', label: 'Solo marcar pagada',
type: 'iconButton', autowidth: true, icon: 'check-circle',
tooltip: 'No afecta a saldos'},
]},
grid_cfdi_por_pagar,
{view: 'label', label: '<b>Facturas a pagar en este depósito: </b>'},
@ -229,6 +457,48 @@ var controls_banco_deposito = [
]
var controls_bank_pay = [
{view: 'toolbar', elements: toolbar_bank_pay},
{view: 'label', label: '<b>Este depósito: </b>'},
{cols: [
{view: 'datepicker', id: 'pay_date', name: 'pay_date',
label: 'Fecha', format: '%d-%M-%Y', labelAlign: 'right',
required: true, invalidMessage: 'Selecciona una fecha',
labelWidth: 125, readonly: true},
{view: 'search', id: 'pay_time', name: 'pay_time', label: 'Hora',
icon: 'clock-o', labelAlign: 'right', required: true,
readonly: true,
invalidMessage: 'Captura una hora'},
{view: 'text', id: 'pay_reference', name: 'pay_reference',
label: 'Referencia', labelAlign: 'right', readonly: true},
]},
{cols: [
{view: 'richselect', id: 'pay_way_payment', readonly: true,
name: 'pay_way_payment', label: 'Forma de Pago', required: true,
options: [], labelWidth: 125, labelAlign: 'right'},
{view: 'currency', type: 'text', id: 'pay_import', name: 'pay_import',
label: 'Importe', labelAlign: 'right', required: true, readonly: true,
invalidMessage: 'Captura un valor númerico', inputAlign: 'right'}
]},
{cols: [
{view: 'textarea', id: 'pay_description', label: 'Descripción',
name: 'pay_description', labelAlign: 'right', required: true,
labelWidth: 125, height: 70, readonly: true},
]},
{view: 'label', label: '<b>Facturas de pago de este depósito: </b>'},
grid_cfdi_pay,
{view: 'label', label: '<b>Facturas relacionadas en este pago: </b>'},
grid_pay_related
]
var controls_bank_invoice_pay = [
{view: 'toolbar', elements: toolbar_bank_invoice_pay},
{view: 'toolbar', elements: toolbar_bank_invoice_pay_filter},
grid_bank_invoice_pay
]
var form_banco_retiro = {
type: 'space',
responsive: true,
@ -255,6 +525,32 @@ var form_banco_deposito = {
}
var form_bank_pay = {
type: 'space',
responsive: true,
cols: [{
view: 'form',
id: 'form_bank_pay',
complexData: true,
scroll: true,
elements: controls_bank_pay,
}],
}
var form_bank_invoice_pay = {
type: 'space',
responsive: true,
cols: [{
view: 'form',
id: 'form_bank_invoice_pay',
complexData: true,
scroll: true,
elements: controls_bank_invoice_pay,
}],
}
var multi_bancos = {
id: 'multi_bancos',
animate: true,
@ -266,7 +562,9 @@ var multi_bancos = {
grid_cuentabanco,
]},
{id: 'banco_retiro', rows: [form_banco_retiro]},
{id: 'banco_deposito', rows: [form_banco_deposito]}
{id: 'banco_deposito', rows: [form_banco_deposito]},
{id: 'bank_pay', rows: [form_bank_pay]},
{id: 'bank_invoice_pay', rows: [form_bank_invoice_pay]}
],
}
@ -282,3 +580,109 @@ var app_bancos = {
}
var win_body_mov_description = {rows: [
{minHeight: 5, maxHeight: 5},
{view: 'textarea', id: 'mov_description', name: 'mov_description',
height: 300},
{minHeight: 5, maxHeight: 5},
{cols: [{},
{view: 'button', id: 'cmd_save_mov_description', autowidth: true,
label: 'Guardar', type: 'iconButton', icon: 'save', hotkey: 'Ctrl+enter'},
{maxWidth: 50},
{view: 'button', id: 'cmd_close_mov_description', autowidth: true,
label: 'Cerrar', type: 'iconButton', icon: 'times-circle', hotkey: 'esc'},
{}]},
{minHeight: 5, maxHeight: 5},
],}
var win_mov_description = {
init: function(){
webix.ui({
view: 'window',
id: 'win_mov_description',
height: 400,
width: 600,
modal: true,
position: 'center',
head: 'Descripción del movimiento',
body: win_body_mov_description,
})
$$('cmd_save_mov_description').attachEvent('onItemClick', cmd_save_mov_description_click)
$$('cmd_close_mov_description').attachEvent('onItemClick', cmd_close_mov_description_click)
}
}
var opt_reasons_cancel_pay = [
{id: '', value: ''},
{id: '01', value: '[01] Comprobante emitido con errores con relación'},
{id: '02', value: '[02] Comprobante emitido con errores sin relación'},
{id: '03', value: '[03] No se llevó acabo la operación'},
{id: '04', value: '[04] Operación nominativa relacionada en una factura global'},
]
var body_invoice_cancel_pay = {rows: [{minHeight: 15},
{view: 'richselect', id: 'lst_reasons_cancel', labelPosition: 'top', label: 'Razón de cancelación', options: opt_reasons_cancel_pay, value: '', width: 400},
{view: 'text', id: 'txt_cancel_uuid', labelPosition: 'top', label: 'UUID que sustituye', width: 400},
{view: 'label', label: 'Esta acción no se puede deshacer', autowidth: true, align: 'center'},
{view: 'label', label: '¿Estás seguro de continuar?', autowidth: true, align: 'center'},
{cols: [{},
{view: 'button', id: 'cmd_invoice_cancel_pay', width: 100, label: 'Cancelar', type: 'danger', icon: 'ban'},
{maxWidth: 25},
{view: 'button', id: 'cmd_win_cancel_pay_close', width: 100, label: 'Cerrar'},
{}
]},
{minHeight: 20},
]}
var win_invoice_cancel_pay = {
init: function(){
webix.ui({
view: 'window',
id: 'win_invoice_cancel_pay',
modal: true,
width: 400,
position: 'center',
head: 'Cancelar CFDI',
body: body_invoice_cancel_pay,
})
$$('cmd_invoice_cancel_pay').attachEvent('onItemClick', cmd_invoice_cancel_pay_click)
$$('cmd_win_cancel_pay_close').attachEvent('onItemClick', cmd_win_cancel_pay_close_click)
}
}
var body_invoice_cancel_pay2 = {rows: [{minHeight: 15},
{view: 'richselect', id: 'lst_reasons_cancel2', labelPosition: 'top', label: 'Razón de cancelación', options: opt_reasons_cancel_pay, value: '', width: 400},
{view: 'text', id: 'txt_cancel_uuid2', labelPosition: 'top', label: 'UUID que sustituye', width: 400},
{view: 'label', label: 'Esta acción no se puede deshacer', autowidth: true, align: 'center'},
{view: 'label', label: '¿Estás seguro de continuar?', autowidth: true, align: 'center'},
{cols: [{},
{view: 'button', id: 'cmd_invoice_cancel_pay2', width: 100, label: 'Cancelar', type: 'danger', icon: 'ban'},
{maxWidth: 25},
{view: 'button', id: 'cmd_win_cancel_pay_close2', width: 100, label: 'Cerrar'},
{}
]},
{minHeight: 20},
]}
var win_invoice_cancel_pay2 = {
init: function(){
webix.ui({
view: 'window',
id: 'win_invoice_cancel_pay2',
modal: true,
width: 400,
position: 'center',
head: 'Cancelar CFDI de Pago',
body: body_invoice_cancel_pay2,
})
$$('cmd_invoice_cancel_pay2').attachEvent('onItemClick', cmd_invoice_cancel_pay2_click)
$$('cmd_win_cancel_pay_close2').attachEvent('onItemClick', cmd_win_cancel_pay_close2_click)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -59,6 +59,11 @@ var menu_user = {
}
var link_blog = "<a class='link_default' target='_blank' href='https://empresalibre.net/blog'>Blog</a>";
var link_forum = "<a class='link_default' target='_blank' href='https://git.cuates.net/elmau/empresa-libre/issues'>Foro</a>";
var link_doc = "<a class='link_default' target='_blank' href='https://empresalibre.net/docs'>Doc</a>";
var ui_main = {
rows: [
{view: 'toolbar', padding: 3, elements: [
@ -69,10 +74,13 @@ var ui_main = {
},
{view: 'label', id: 'lbl_title_main', label: '<b>Empresa Libre</b>'},
{},
{view: 'label', id: 'lbl_blog', label: link_blog, align: 'right', width: 30},
{view: 'label', id: 'lbl_forum', label: link_forum, align: 'right', width: 30},
{view: 'label', id: 'lbl_doc', label: link_doc, align: 'right', width: 25},
menu_user,
{view: 'button', id: 'cmd_update_timbres', type: 'icon', width: 45,
css: 'app_button', icon: 'bell-o', badge: 0},
{view: 'button', type: 'icon', width: 45, css: 'app_button',
{view: 'button', type: 'icon', width: 30, css: 'app_button',
icon: 'cogs', id: 'cmd_ir_al_admin', hidden: true,
click: 'cmd_ir_al_admin_click'}
]

View File

@ -20,6 +20,8 @@ var toolbar_nomina_util = [
type: 'iconButton', autowidth: true, icon: 'check-circle'},
{view: 'button', id: 'cmd_nomina_log', label: 'Log',
type: 'iconButton', autowidth: true, icon: 'download'},
{view: 'button', id: 'cmd_nomina_download', label: 'Descargar',
type: 'iconButton', autowidth: true, icon: 'download'},
{},
{view: 'button', id: 'cmd_nomina_cancel', label: 'Cancelar',
type: 'iconButton', autowidth: true, icon: 'ban'},
@ -46,6 +48,8 @@ var grid_cols_nomina = [
{id: "serie", header: ["Serie"], adjust: "header"},
{id: 'folio', header: ['Folio', {content: 'numberFilter'}], adjust: 'header',
sort: 'int', css: 'right', footer: {text: 'Recibos', colspan: 3}},
{id: "uuid", header: ["UUID", {content: "textFilter"}], adjust: "data",
sort:"string", hidden:true},
{id: "fecha", header: ["Fecha y Hora"], adjust: "data", sort: "string"},
{id: "estatus", header: ["Estatus", {content: "selectFilter"}],
adjust: "data", sort:"string"},
@ -53,11 +57,12 @@ var grid_cols_nomina = [
adjust: 'data', sort: 'string'},
{id: 'total', header: ['Total', {content: 'numberFilter'}], width: 150,
sort: 'int', format: webix.i18n.priceFormat, css: 'right',
footer: {content: 'summActive', css: 'right'}},
footer: {content: 'summTimbradaN', css: 'right'}},
{id: "empleado", header: ["Empleado", {content: "selectFilter"}],
fillspace:true, sort:"string"},
fillspace:true, sort:"string", footer: {text: '$ 0.00'}},
{id: 'xml', header: 'XML', adjust: 'data', template: get_icon('xml')},
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
{id: 'email', header: '@', adjust: 'data', template: get_icon('email')}
]
@ -240,3 +245,44 @@ var win_import_nomina = {
$$('up_nomina').attachEvent('onUploadComplete', up_nomina_upload_complete)
}
}
var opt_reasons_cancel_nomina = [
{id: '', value: ''},
{id: '01', value: '[01] Comprobante emitido con errores con relación'},
{id: '02', value: '[02] Comprobante emitido con errores sin relación'},
{id: '03', value: '[03] No se llevó acabo la operación'},
{id: '04', value: '[04] Operación nominativa relacionada en una factura global'},
]
var body_invoice_cancel_nomina = {rows: [{minHeight: 15},
{view: 'richselect', id: 'lst_reasons_cancel', labelPosition: 'top', label: 'Razón de cancelación', options: opt_reasons_cancel_pay, value: '', width: 400},
{view: 'text', id: 'txt_cancel_uuid', labelPosition: 'top', label: 'UUID que sustituye', width: 400},
{view: 'label', label: 'Esta acción no se puede deshacer', autowidth: true, align: 'center'},
{view: 'label', label: '¿Estás segura de continuar?', autowidth: true, align: 'center'},
{cols: [{},
{view: 'button', id: 'cmd_invoice_cancel_nomina', width: 100, label: 'Cancelar', type: 'danger', icon: 'ban'},
{maxWidth: 25},
{view: 'button', id: 'cmd_win_cancel_nomina_close', width: 100, label: 'Cerrar'},
{}
]},
{minHeight: 20},
]}
var win_invoice_cancel_nomina = {
init: function(){
webix.ui({
view: 'window',
id: 'win_invoice_cancel_nomina',
modal: true,
width: 400,
position: 'center',
head: 'Cancelar CFDI',
body: body_invoice_cancel_nomina,
})
$$('cmd_invoice_cancel_nomina').attachEvent('onItemClick', cmd_invoice_cancel_nomina_click)
$$('cmd_win_cancel_nomina_close').attachEvent('onItemClick', cmd_win_cancel_nomina_close_click)
}
}

View File

@ -1,3 +1,18 @@
//~ Empresa Libre
//~ Copyright (C) 2016-2018 Mauricio Baeza Servin (web@correolibre.net)
//~
//~ This program is free software: you can redistribute it and/or modify
//~ it under the terms of the GNU General Public License as published by
//~ the Free Software Foundation, either version 3 of the License, or
//~ (at your option) any later version.
//~
//~ This program is distributed in the hope that it will be useful,
//~ but WITHOUT ANY WARRANTY; without even the implied warranty of
//~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//~ GNU General Public License for more details.
//~
//~ You should have received a copy of the GNU General Public License
//~ along with this program. If not, see <http://www.gnu.org/licenses/>.
var toolbar_partners = [
@ -8,8 +23,8 @@ var toolbar_partners = [
{view: 'button', id: 'cmd_delete_partner', label: 'Eliminar', type: 'iconButton',
autowidth: true, icon: 'user-times'},
{},
{view: 'button', id: 'cmd_partner_zero', label: 'Saldo 0', type: 'iconButton',
autowidth: true, icon: 'power-off', disabled: true},
//~ {view: 'button', id: 'cmd_partner_zero', label: 'Saldo 0', type: 'iconButton',
//~ autowidth: true, icon: 'power-off', disabled: true},
]
@ -81,7 +96,7 @@ var controls_fiscales = [
{cols: [{view: 'text', id: 'no_interior', name: 'no_interior', width: 300,
label: 'No Interior: '},{}]},
{cols: [{view: 'search', id: 'codigo_postal', name: 'codigo_postal',
width: 300, label: 'C.P.: ', attributes: {maxlength: 5}},{}]},
width: 300, label: 'C.P.: ', attributes: {maxlength: 5}, required: true},{}]},
{view: 'text', id: 'colonia', name: 'colonia', label: 'Colonia: '},
{view: 'text', id: 'municipio', name: 'municipio', label: 'Municipio: '},
{view: 'text', id: 'estado', name: 'estado', label: 'Estado: '},
@ -107,25 +122,41 @@ var controls_fiscales = [
{view: 'richselect', id: 'lst_uso_cfdi_socio', name: 'uso_cfdi_socio',
label: 'Uso del CFDI', options: []},
{},
]},
{template: 'Regimenes Fiscales', type: 'section'},
{cols: [
{view: 'list', id: 'lst_receptor_regimenes_fiscales', data: [],
select: 'multiselect', width: 600, height: 125, required: true},
{},
]}
]
var controls_others = [
{view: 'checkbox', id: 'es_activo', name: 'es_activo', label: 'Activo: ',
value: true, bottomLabel: '&nbsp;&nbsp;&nbsp;Se recomienda solo desactivar y no eliminar'},
value: true, bottomLabel: '&nbsp;&nbsp;Se recomienda solo desactivar y no eliminar'},
{view: 'text', id: 'commercial_name', name: 'nombre_comercial',
label: 'Nombre Comercial: '},
{view: 'text', id: 'telefonos', name: 'telefonos', label: 'Teléfonos: '},
{view: 'text', id: 'web', name: 'web', label: 'Página Web: '},
{cols: [
{view: 'text', id: 'correo_facturas', name: 'correo_facturas',
label: 'Correos para Facturas: ', tooltip: 'Separados por comas',
bottomLabel: 'Uno o más correos electrónicos separados por comas'},
{view: 'text', id: 'partner_email_fp', name: 'partner_email_fp',
label: 'Para Facturas de pago: ', tooltip: 'Separados por comas',
bottomLabel: 'Uno o más correos electrónicos separados por comas'},
]},
{cols: [
{view: 'checkbox', id: 'es_cliente', name: 'es_cliente',
label: 'Es Cliente: ', value: true, width: 180},
{view: 'text', id: 'cuenta_cliente', name: 'cuenta_cliente',
label: 'Cuenta Cliente: ', disabled: true}, {}]
label: 'Cuenta Cliente: ', disabled: true},
{view: "currency", type: "text", id: 'partner_balance', width: 300,
name: 'partner_balance', label: 'Saldo', labelWidth: 100,
labelAlign: "right", required: true, inputAlign: "right",
invalidMessage: "Captura un valor númerico", readonly: true},
]
},
{cols: [
{view: 'checkbox', id: 'es_proveedor', name: 'es_proveedor',
@ -134,12 +165,56 @@ var controls_others = [
label: 'Cuenta Proveedor: ', disabled: true}, {}]
},
{view: 'checkbox', name: 'es_ong', label: 'Es ONG: ', value: false},
{view: 'text', name: 'tags', label: 'Etiquetas',
{view: 'text', name: 'tags', label: 'Etiquetas', disabled: true,
tooltip: 'Utiles para filtrados rápidos. Separa por comas.'},
{view: 'textarea' , height: 200, name: 'notas', label: 'Notas'},
]
var grid_partner_account_bank_cols = [
{id: 'id', header: 'ID', hidden: true},
{id: 'delete', header: '', width: 30, css: 'delete'},
{id: 'banco', header: 'Banco', fillspace: 1},
{id: 'cuenta', header: 'Cuenta', fillspace: 1},
{id: 'clabe', header: 'CLABE', fillspace: 1},
//~ {id: 'moneda', header: 'Moneda', fillspace: 1},
]
var grid_partner_account_bank = {
view: 'datatable',
id: 'grid_partner_account_bank',
select: 'row',
adjust: true,
autoheight: true,
columns: grid_partner_account_bank_cols,
}
var controls_partner_bank = [
{template: 'Agregar cuenta de banco', type: 'section'},
{view: 'form', id: 'form_partner_account_bank', rows: [
{cols: [
{view: 'richselect', id: 'lst_partner_bank', name: 'partner_bank',
label: 'Banco: ', required: true, options: []},
{view: 'text', id: 'partner_account', name: 'partner_account',
label: 'Cuenta: ', required: true},
{view: 'text', id: 'partner_clabe', name: 'partner_clabe',
label: 'CLABE: ', required: true},
]},
{minHeight: 10},
{cols: [{},
{view: 'button', id: 'cmd_partner_add_account_bank', maxWidth: 200,
label: 'Agregar cuenta'},
{}]},
],
},
{minHeight: 20, maxHeight: 20},
{template: 'Cuentas de banco existentes', type: 'section'},
grid_partner_account_bank,
{minHeight: 50},
]
var toolbar_contacts = [
{view: 'button', id: 'cmd_new_contact', label: 'Nuevo', type: 'iconButton',
@ -277,11 +352,12 @@ var controls_partner = [
{
view: 'tabview',
id: 'tab_partner',
tabbar: {options: ['Datos Fiscales', 'Otros Datos', 'Contactos']}, animate: true,
tabbar: {ptions: ['Datos Fiscales', 'Otros Datos', 'Cuentas de Banco']},
animate: true,
cells: [
{id: 'Datos Fiscales', rows: controls_fiscales},
{id: 'Otros Datos', rows: controls_others},
{id: 'Contactos', rows: [multi_contacts]},
{id: 'Cuentas de Banco', rows: controls_partner_bank}
]
},
{rows: [

View File

@ -10,6 +10,12 @@ var toolbar_products = [
{},
{view: 'button', id: 'cmd_import_products', label: 'Importar',
type: 'iconButton', autowidth: true, icon: 'upload'},
{view: "button", id: "cmd_add_inventory", label: "Altas", hidden: true,
type: "iconButton", autowidth: true, icon: "plus"},
{view: "button", id: "cmd_products_add", label: "Altas CFDI", hidden: true,
type: "iconButton", autowidth: true, icon: "plus"},
{view: 'button', id: 'cmd_show_exists', label: 'Existencias', hidden: true,
type: 'iconButton', autowidth: true, icon: 'table'},
]
@ -24,7 +30,7 @@ var grid_products_cols = [
{ id: "unidad", header: ["Unidad", {content: "selectFilter"}], width: 150,
sort:"string" },
{ id: "valor_unitario", header: ["Precio", {content: "numberFilter"}],
width: 150, sort: 'int', format: webix.i18n.priceFormat, css: "right" },
width: 150, sort: 'int', format: format_currency, css: "right" },
{ id: 'existencia', header: ['Existencia', {content: 'numberFilter'}],
width: 100, sort: 'int', format: webix.i18n.numberFormat,
hidden: true, css: 'right' },
@ -105,6 +111,15 @@ var suggest_sat_producto = {
}
var opt_tax_object = [
{id: '01', value: '[01] No objeto de impuesto.'},
{id: '02', value: '[02] Sí objeto de impuesto.'},
{id: '03', value: '[03] Sí objeto del impuesto y no obligado al desglose.'},
{id: '04', value: '[04] Sí objeto del impuesto y no causa impuesto.'},
{id: '05', value: '[05] Sí objeto del impuesto, IVA crédito PODEBI.'},
]
var controls_generals = [
{view: 'checkbox', id: 'es_activo_producto', name: 'es_activo_producto',
label: 'Activo: ', value: true,
@ -135,9 +150,10 @@ var controls_generals = [
{view: "richselect", id: "unidad", name: "unidad", label: "Unidad",
width: 300, labelWidth: 130, labelAlign: "right", required: true,
invalidMessage: "La Unidad es requerida", options: []},
{view: 'text', id: 'tags_producto', name: 'tags_producto',
labelAlign: 'right', label: 'Etiquetas',
placeholder: 'Separadas por comas'}
{view: 'richselect', id: 'objeto_impuesto', name: 'objeto_impuesto', label: 'Objeto de Impuestos',
width: 500, labelWidth: 150, labelAlign: "right", required: true,
invalidMessage: 'Este campo es requerido', options: opt_tax_object},
{},
]},
{cols: [
{view: "currency", type: "text", id: "valor_unitario",
@ -154,7 +170,7 @@ var controls_generals = [
label: 'Inventario', labelAlign: 'right', labelWidth: 130},
{view: 'counter', id: 'txt_existencia', name: 'existencia',
hidden: true, label: 'Existencia', step: 5, value: 0, min: 0,
disabled: true},
disabled: true, readonly: true},
{view: 'counter', id: 'txt_minimo', name: 'minimo', hidden: true,
label: 'Mínimo', step: 5, value: 0, min: 0, disabled: true},
{},]},
@ -172,8 +188,8 @@ var controls_products = [
],
},
{rows: [
{ template:"", type: "section" },
{ margin: 10, cols: [{},
{template: "", type: "section"},
{margin: 10, cols: [{},
{view: "button", id: "cmd_save_product", label: "Guardar" , type: "form", autowidth: true, align:"center"},
{view: "button", id: "cmd_cancel_product", label: "Cancelar" , type: "danger", autowidth: true, align:"center"},
{}]
@ -198,6 +214,129 @@ var form_product = {
}
var toolbar_products_add = {view: 'toolbar', elements: [{},
{view: 'button', id: 'cmd_add_products_from_xml', label: 'Desde XML',
type: 'iconButton', autowidth: true, icon: 'upload'},
{}]}
var rows_pro_add_partner = [
{view: 'fieldset', label: 'Buscar Proveedor', body: {rows: [
{cols: [
{view: 'search', id: 'search_partner_id', label: 'por Clave',
labelPosition: 'top', maxWidth: 200, placeholder: 'Captura la clave'},
{view: 'search', id: 'search_partner_name', label: 'por Nombre o RFC',
labelPosition: 'top', placeholder: 'Captura al menos tres letras'},
]},
{cols: [
{view: 'label', id: 'lbl_partner_title', label: 'Seleccionado: ', autowidth: true},
{view: 'label', id: 'lbl_partner', label: 'Ninguno'},
]}
]}},
]
var grid_partner_products_cols = [
{id: 'select', header: '', template:'{common.checkbox()}', width:35},
{id: 'key', header: {text: 'Clave', css: 'center'}, width: 100,
adjust: 'data'},
{id: 'key_sat', header:{text: 'Clave SAT', css: 'center'}, width: 100,
adjust: 'data'},
{id: 'description', header:{text: 'Descripción', css: 'center'},
fillspace: true},
{id: "pedimento", header: 'Pedimento', editor: 'text', hidden: true},
{id: 'unit', header:{text: 'Unidad', css: 'center'}, width: 100,
adjust: 'data'},
{id: 'unit_value', header:{text: 'Valor Unitario', css: 'center'},
width: 100, format: format_currency, css: 'right'},
{id: 'cant', header: {text: 'Cantidad', css: 'center'}, width: 50,
format: webix.i18n.numberFormat, css: 'right'},
{id: 'separate', header: '', width: 25},
{id: 'id_product', header: '', hidden: true},
{id: 'key1', header:{text: 'Clave', css: 'center'}, width: 100,
adjust: true, editor: 'text', hidden: true},
{id: 'key_sat1', header:{text: 'Clave SAT', css: 'center'}, width: 100,
adjust: true, editor: 'text'},
{id: 'description1', header:{text: 'Descripción', css: 'center'},
fillspace: true, editor: 'popup'},
{id: 'unit_value1', header:{text: 'Valor Unitario', css: 'center'},
width: 100, format: format_currency, css: 'right', editor: 'text'},
{id: 'cant1', header: {text: 'Cantidad', css: 'center'}, width: 50,
format: webix.i18n.numberFormat, css: 'right', editor: 'text'},
]
var grid_partner_products = {
view: 'datatable',
id: 'grid_partner_products',
select: 'row',
adjust: true,
autoheight: true,
editable: true,
columns: grid_partner_products_cols,
data: [],
fixedRowHeight: false,
on:{
onCheck:function(rowId, colId, state){
grid_partner_products_select(rowId, state);
}
}
}
var controls_products_add = [
{minHeight: 10, maxHeight: 10},
toolbar_products_add,
{minHeight: 10, maxHeight: 10},
{cols: [
{rows: rows_pro_add_partner},
{maxWidth: 10},
{},
]},
{view: 'label', label: 'Detalle', height: 30, align: 'left'},
{cols: [
grid_partner_products,
//~ grid_products_add,
]},
{rows: [
{template:"", type: "section" },
{margin: 10, cols: [{},
{view: 'button', id: 'cmd_save_products_add', label: 'Guardar',
autowidth: true, align: 'center'},
{},
{view: 'button', id: 'cmd_close_products_add', label: 'Cancelar',
type: 'danger', autowidth: true, align: 'center'}
]
},
]}
]
var controls_form_products_add = [
{
view: 'tabview',
id: 'tv_invoice',
animate: true,
cells: [
{id: 'Altas a inventario', rows: controls_products_add},
]
},
]
var form_products_add = {
type: 'space',
responsive: true,
cols: [{
view: 'form',
id: 'form_products_add',
complexData: true,
scroll: true,
elements: controls_form_products_add,
}]
}
var multi_products = {
id: "multi_products",
animate: true,
@ -206,7 +345,8 @@ var multi_products = {
{view:"toolbar", elements: toolbar_products},
grid_products,
]},
{id: "product_new", rows:[form_product]}
{id: "product_new", rows:[form_product]},
{id: "product_add", rows:[form_products_add]}
],
}
@ -250,4 +390,152 @@ var win_import_products = {
$$('cmd_upload_products').attachEvent('onItemClick', cmd_upload_products_click)
$$('up_products').attachEvent('onUploadComplete', up_products_upload_complete)
}
}
}
var body_add_products_from_xml = {rows: [
{view: 'form', id: 'form_upload_products_from_xml', rows: [
{cols: [{},
{view: 'uploader', id: 'up_products_from_xml', autosend: false,
link: 'lst_up_products_from_xml', value: 'Seleccionar Archivo',
upload: '/files/productsadd'}, {}]},
{cols: [
{view: 'list', id: 'lst_up_products_from_xml', type: 'uploader',
autoheight: true, borderless: true}]},
{cols: [{}, {view: 'button', id: 'cmd_upload_products_from_xml',
label: 'Cargar Productos'}, {}]},
]},
]}
var win_add_products_from_xml = {
init: function(){
webix.ui({
view: 'window',
id: 'win_add_products_from_xml',
width: 400,
modal: true,
position: 'center',
head: 'Agregar Productos desde XML',
body: body_add_products_from_xml,
})
$$('cmd_upload_products_from_xml').attachEvent('onItemClick', cmd_upload_products_from_xml_click)
$$('up_products_from_xml').attachEvent('onUploadComplete', up_products_from_xml_upload_complete)
}
}
var body_add_inventory = {rows: [{minHeight: 10},
{view: 'text', id: 'txt_add_id', readonly: true, hidden: true},
{cols: [
{view: 'text', id: 'txt_add_key', label: 'Clave',
labelPosition: 'top', readonly: true},
{view: 'text', id: 'txt_add_unit', label: 'Unidad',
labelPosition: 'top', readonly: true},
]},
{view: 'textarea', id: 'txt_add_description', height: 100,
label: 'Descripción', readonly: true, labelPosition: 'top'},
{minHeight: 10},
{cols: [
{view: 'counter', id: 'txt_new_cant', label: 'Cantidad a agregar',
labelWidth: 'auto', step: 1, value: 0, min: 0.01},
{view: 'richselect', id: 'lst_warehouses', label: 'Almacen: ',
labelPosition: 'left', required: false, options: [], hidden: false},
]},
{minHeight: 20},
{cols: [{},
{view: 'button', id: 'cmd_add_inventory_save', label: 'Guardar'}, {},
{view: 'button', id: 'cmd_add_inventory_cancel', label: 'Cancelar', type: 'danger'}, {}
]},
{minHeight: 20},
]}
var win_add_inventory = {
init: function(){
webix.ui({
view: 'window',
id: 'win_add_inventory',
width: 600,
modal: true,
position: 'center',
head: 'Agregar entrada manualmente',
body: body_add_inventory,
})
$$('cmd_add_inventory_save').attachEvent('onItemClick', cmd_add_inventory_save_click)
$$('cmd_add_inventory_cancel').attachEvent('onItemClick', cmd_add_inventory_cancel_click)
}
}
var grid_warehouse_exists_cols = [
{ id: 'id', header: 'ID', width: 75, hidden: true},
{ id: 'warehouse', header: ['Almacen'], fillspace:true,
footer: {text: 'Total', css: 'right'}},
{ id: 'exists', header: ['Existencia'], width: 100, sort: 'int',
format: webix.i18n.numberFormat, css: 'right',
footer: {content: 'summColumn', css: 'right'} },
]
var grid_warehouse_exists = {
view: 'datatable',
id: 'grid_warehouse_exists',
adjust: true,
autoheight: true,
select: 'row',
footer: true,
columns: grid_warehouse_exists_cols,
}
var body_win_show_exists = {rows: [{maxHeight: 10, minHeight: 10},
{minWidth: 500},
{cols: [
{maxWidth: 10},
{view: 'text', id: 'txt_id_product', readonly: true, hidden: true},
grid_warehouse_exists,
{maxWidth: 10}
]},
{maxHeight: 10},
{cols: [{maxWidth: 10},
{view: 'label', id: 'lbl_title_move', label: 'Primero, selecciona el almacen origen en la tabla superior.'},
]},
{cols: [{maxWidth: 10},
{view: 'counter', id: 'txt_cant_to_move', label: 'Cantidad a mover:',
labelPosition: 'top', step: 1, value: 0, min: 0.01},
{view: 'richselect', id: 'lst_warehouse_target', label: 'Almacen destino: ',
labelPosition: 'top', required: false, options: []}, {maxWidth: 10},
{view: 'button', id: 'cmd_warehouse_move', label: 'Mover', maxWidth: 100},
{maxWidth: 10}]},
{minHeight: 25, maxHeight: 25},
{template: 'Ajuste de almacen', type: 'section'},
{cols: [{maxWidth: 10},
{view: 'counter', id: 'txt_cant_to_adjust', label: 'Cantidad a ajustar:',
labelPosition: 'top', step: 1, value: 0, min: -1000000},
{view: 'button', id: 'cmd_adjust_stock', label: 'Ajustar', maxWidth: 100},
{maxWidth: 10}]},
{maxHeight: 20, minHeight: 20},
{cols: [{},
{view: 'button', id: 'cmd_win_show_exists_close', label: 'Cerrar', type: 'danger'},
{}]},
{maxHeight: 20, minHeight: 20},
]}
var win_show_exists = {
init: function(){
webix.ui({
view: 'window',
id: 'win_show_exists',
width: 500,
modal: true,
position: 'center',
head: 'Existencia por Almacen',
body: body_win_show_exists,
})
$$('cmd_win_show_exists_close').attachEvent('onItemClick', cmd_win_show_exists_close_click)
$$('cmd_warehouse_move').attachEvent('onItemClick', cmd_warehouse_move_click)
$$('cmd_adjust_stock').attachEvent('onItemClick', cmd_adjust_stock_click)
}
}

View File

@ -3,6 +3,8 @@
var toolbar_tickets = [
{view: 'button', id: 'cmd_nuevo_ticket', label: 'Nuevo', type: 'iconButton',
autowidth: true, icon: 'plus'},
{view: 'button', id: 'cmd_ticket_from_ticket', label: 'Regenerar',
type: 'iconButton', autowidth: true, icon: 'pencil'},
{view: 'button', id: 'cmd_ticket_to_invoice', label: 'Facturar',
type: 'iconButton', autowidth: true, icon: 'file-code-o'},
{},
@ -145,6 +147,8 @@ var grid_tdetails_cols = [
{id: "importe", header:{text: 'Importe', css: 'center'}, width: 150,
format: webix.i18n.priceFormat, css: 'right',
footer: {content: 'summColumn', css: 'right_footer2'}},
{id: "inventario", hidden: true},
{id: "existencia", hidden: true},
]
@ -231,7 +235,12 @@ var cells_new_ticket = [
var toolbar_ticket_invoice = {view: 'toolbar', elements: [{},
{view: 'checkbox', id: 'chk_is_invoice_day', labelWidth: 0, width: 150,
labelRight: 'Es factura del día'}, {},
labelRight: 'Es Factura Global'},
{view: 'richselect', id: 'lst_global_periodicidad_2', labelWidth: 90, width: 225,
label: 'Periodicidad:', options: opt_global_periodicidad, value: '01', disabled: true},
{view: 'richselect', id: 'lst_global_months_2', labelWidth: 50, width: 250,
label: 'Mes:', options: opt_global_months, value: '01', disabled: true},
{},
{view: 'button', id: 'cmd_close_ticket_invoice', label: 'Cerrar',
type: 'danger', autowidth: true, align: 'center'}
]}
@ -302,6 +311,7 @@ var grid_tickets_active = {
view: 'datatable',
id: 'grid_tickets_active',
select: 'row',
multiselect: true,
adjust: true,
footer: true,
drag: true,
@ -337,6 +347,7 @@ var grid_tickets_invoice = {
view: 'datatable',
id: 'grid_tickets_invoice',
select: 'row',
multiselect: true,
adjust: true,
footer: true,
drag: true,
@ -478,4 +489,4 @@ var win_ticket_notes = {
})
$$('cmd_ticket_save_note').attachEvent('onItemClick', cmd_ticket_save_note_click)
}
}
}

11573
source/static/js/webix.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,8 @@
<%inherit file="base.html"/>
<%block name="media">
<link rel="stylesheet" href="/static/css/sidebar_air.css" type="text/css">
<link rel="stylesheet" href="/static/css/app.css" type="text/css">
<script src="/static/js/sidebar.js" type="text/javascript" ></script>
<script src="/static/js/controller/util.js" type="text/javascript" ></script>
<script src="/static/js/ui/admin.js" type="text/javascript" ></script>
<script src="/static/js/controller/admin.js" type="text/javascript" ></script>
</%block>
<%block name="content">

View File

@ -6,10 +6,13 @@
<meta charset="utf-8" />
<link rel="shortcut icon" href="/static/img/favicon.png">
<link rel="stylesheet" href="/static/css/air.css" type="text/css">
<link rel="stylesheet" href="/static/css/sidebar_air.css" type="text/css">
<link rel="stylesheet" href="/static/css/app.css" type="text/css">
<script src="/static/js/webix.js" type="text/javascript" ></script>
<script src="/static/js/es-MX.js" type="text/javascript" ></script>
<script src="/static/js/lokijs.min.js" type="text/javascript" ></script>
<script src="/static/js/controller/util.js" type="text/javascript" ></script>
<%block name="media"/>
</head>
@ -17,7 +20,7 @@
<body>
<script type="text/javascript" charset="utf-8">
webix.debug = true;
webix.debug = false;
webix.i18n.setLocale("es-MX");
</script>

View File

@ -40,6 +40,7 @@ webix.ready(function(){
var value = data.json();
$$("title_login").setHTML(value);
})
$$("txt_rfc").focus();
});
</script>

View File

@ -1,10 +1,6 @@
<%inherit file="base.html"/>
<%block name="media">
<link rel="stylesheet" href="/static/css/sidebar_air.css" type="text/css">
<script src="/static/js/sidebar.js" type="text/javascript" ></script>
<script src="/static/js/controller/util.js" type="text/javascript" ></script>
<script src="/static/js/ui/partners.js" type="text/javascript" ></script>
<script src="/static/js/ui/products.js" type="text/javascript" ></script>
<script src="/static/js/ui/bancos.js" type="text/javascript" ></script>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,204 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="/static/css/${rfc}.css">
<title>Empresa Libre</title>
</head>
<body>
<div id="plantilla">
<div class="cancelada" style="display: ${cancelada}">
Cancelada
<div>Sin valor fiscal</div>
</div>
<header>
<section class="emisor-cintilla">
${emisor_calle} ${emisor_noexterior} ${emisor_nointerior}
${emisor_colonia} ${emisor_codigopostal} ${emisor_municipio}
${emisor_estado} ${emisor_pais}
</section>
<section class="datos-emisor">
<img src="/static/img/${emisor_logo}.png" class="logo"/>
<section class="fiscales-emisor">
<div class="nombre">
${emisor_nombre}
</div>
<div class="rfc">
${emisor_rfc}
</div>
<div class="regimen">
${emisor_regimenfiscal}
</div>
<div class="telefono">
(55) 5810-8088
<img src="/static/img/telefono.png" />
</div>
<div class="correo">
administracion@empresalibre.net
<img src="/static/img/correo.png" />
</div>
<div class="web">
https://empresalibre.net
<img src="/static/img/web.png" />
</div>
</section>
<div class="clear"></div>
<section class="receptor">
<div class="titulo-vertical">Receptor</div>
<div class="nombre">
${receptor_nombre}
</div>
<div class="rfc">
${receptor_rfc}
</div>
<div class="direccion">
${receptor_calle} ${receptor_noexterior} ${receptor_nointerior}
${receptor_colonia} ${receptor_codigopostal}
</div>
<div class="estado">
${receptor_municipio} ${receptor_estado} ${receptor_pais}
</div>
<div class="correo">
<img src="/static/img/correo.png" /> ${receptor_correo_1}
</div>
<div class="clear"></div>
<div class="uso-cfdi">
${receptor_usocfdi}
</div>
<div class="telefono">
<img src="/static/img/telefono.png" /> ${receptor_telefono_1}
</div>
</section>
<section class="cfdi">
<div class="titulo-vertical">Datos CFDI</div>
<div class="folio">Folio: <span>${cfdi_serie}-${cfdi_folio}</span></div>
<div class="tipo">Tipo: <span>${cfdi_tipodecomprobante}</span></div>
<div class="clear"></div>
<div class="folio-fiscal">
Folio Fiscal <br>
<span>${timbre_uuid}</span>
</div>
<div class="fecha-emision">Fecha Emisión: ${cfdi_fecha}</div>
<div class="fecha-certificacion">Fecha Certificacion: ${timbre_fechatimbrado}</div>
<div class="lugar-expedicion">CP de Expedición: ${cfdi_lugarexpedicion}</div>
</section>
</section>
</header>
<div class="clear"></div>
<table class="conceptos">
<thead>
<tr>
<th class="clave">Clave</th>
<th class="descripcion">Descripción</th>
<th class="unidad">Unidad</th>
<th class="cantidad">Cantidad</th>
<th class="valor-unitario">Valor Unitario</th>
<th class="importe">Importe</th>
</tr>
</thead>
<tbody>
% for c in conceptos:
<tr>
<td class="clave">${c['clave']}</td>
<td class="descripcion"><div>${c['descripcion']}</div></td>
<td class="unidad">${c['unidad']}</td>
<td class="cantidad">${c['cantidad']}</td>
<td class="valor-unitario">${c['valorunitario']}</td>
<td class="importe">${c['importe']}</td>
</tr>
% endfor
</tbody>
</table>
<div class="total-letras">
${cfdi_totalenletras}
<!--
<div class="condiciones-pago">
${cfdi_condicionespago}
</div>
<div class="formapago-metodopago">
${cfdi_formapago}<BR>${cfdi_metodopago}
</div>
<div class="moneda-tipocambio">
${cfdi_moneda}, Tipo de Cambio: ${cfdi_tipocambio}
</div>
<div class="tiporelacion">
TIPO de ${cfdi_tiporelacion}
</div>
<div class="relacionados">
RELACIONADS${cfdi_relacionados}
NOFzxd
</div>
<div class="notas">
NOTAS ${cfdi_notas}
</div>
-->
<div class="factura-info">
${cfdi_condicionespago}<BR>
${cfdi_formapago}<BR>
${cfdi_metodopago}<BR>
${cfdi_moneda}, Tipo de Cambio: ${cfdi_tipocambio}<BR>
${cfdi_tiporelacion}<BR>
${cfdi_relacionados}<BR>
${cfdi_notas}
</div>
</div>
<table class="subtotal">
% for total in totales:
<tr>
<th>${total[0]}</th>
<td>${total[1]}</td>
</tr>
% endfor
</table>
<!--
<div class="clear"></div>
<div class="tipocomite">
{ine.tipocomite}
</div>
<div class="tipoproceso">
{ine.tipoproceso}
</div>
<div class="idcontabilidad">
{ine.idcontabilidad}
</div>
-->
<div class="clear"></div>
<div class="sello">
<img id="id_cbb" class="cbb" src="${cbb}" />
<div class="cadenas-sello">
<div class="cadena">
Sello Digital del CFDI:
<div>
${cfdi_sello}
</div>
</div>
<div class="cadena">
Sello del SAT:
<div>
${timbre_sellosat}
</div>
</div>
</div>
</div>
<div class="clear"></div>
<div class="cadena-original">
Cadena original del complemento de certificación digital del SAT:
<div>
${timbre_cadenaoriginal}
</div>
</div>
<div class="clear"></div>
<div class="rfc-pac">
RFC del PAC que Certifico: ${timbre_rfcprovcertif}
Serie CSD SAT: ${timbre_nocertificadosat}
Serie CSD Emisor: ${cfdi_nocertificado}
</div>
</div>
</body>
</html>

View File

@ -1,4 +1,5 @@
{
"colores": {"piepagina": "darkred"},
"encabezado": {
"emisor": {
"direccion": {
@ -208,10 +209,9 @@
"estilo": {"name": "tipocambio", "fontName": "Helvetica",
"fontSize": 7, "alignment": 0, "textColor": "black"}
},
"leyenda": {
"estilo": {"name": "leyenda", "fontName": "Helvetica-Bold",
"fontSize": 6, "alignment": 1, "textColor": "black",
"spaceBefore": 0.2}
"notas": {
"estilo": {"name": "notas", "fontName": "Helvetica",
"fontSize": 7, "alignment": 0, "textColor": "black"}
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More