Merge branch 'dev' of https://git.verdnatura.es/salix into dev

This commit is contained in:
Javi Gallego 2018-03-24 17:56:49 +01:00
commit 169c0c6000
101 changed files with 5251 additions and 468 deletions

View File

@ -8,14 +8,26 @@ Salix is also the scientific name of a beautifull tree! :)
Required applications.
* Visual Studio Code
* Node.js = 8.9.4
* NGINX
* Docker
In Visual Studio Code we use the ESLint extension. Open Visual Studio Code, press Ctrl+P and paste the following command
```
ext install dbaeumer.vscode-eslint
```
You will need to install globally the following items.
```
$ npm install -g karma-cli gulp webpack nodemon
```
## Linux Only Prerequisites
Your user must be on the docker group to use it so you will need to run this command:
```
$ sudo usermod -G docker yourusername
```
## Getting Started // Installing

View File

@ -1,119 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:ns="&amp;#38;ns_sfw;"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="400"
height="168.56424"
viewBox="0 0 400 168.56424"
enable-background="new 0 0 560 960"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="logo.svg"><defs
id="defs43" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1016"
id="namedview41"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="3.09"
inkscape:cx="200"
inkscape:cy="84.28212"
inkscape:window-x="1920"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" /><metadata
id="metadata3"><ns:sfw><ns:slices /><ns:sliceSourceBounds
height="212.103"
width="503.32"
y="-235.507"
x="28.34"
bottomLeftOrigin="true" /></ns:sfw><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><g
id="g5"
transform="matrix(0.79472445,0,0,0.79472445,-22.522491,-18.600526)"><g
id="g7"><path
d="M 51.517,90.859 28.34,23.407 l 18.318,0 9.479,34.665 0.776,2.839 c 1.158,4.151 2.041,7.632 2.65,10.44 0.336,-1.372 0.747,-2.992 1.234,-4.854 0.487,-1.862 1.174,-4.306 2.057,-7.328 l 9.942,-35.763 18.22,0 -23.361,67.453 -16.138,0 z"
id="path9"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#3e3d3d;fill-rule:evenodd" /><path
d="m 523.891,90.859 -16.591,0 c 0.036,-0.791 0.106,-1.614 0.209,-2.466 l 0.354,-2.653 c -2.932,2.285 -5.847,3.974 -8.737,5.071 -2.892,1.096 -5.879,1.644 -8.969,1.644 -4.8,0 -8.23,-1.32 -10.289,-3.957 -2.061,-2.639 -2.463,-6.202 -1.207,-10.688 1.154,-4.121 3.184,-7.47 6.091,-10.048 2.904,-2.577 6.718,-4.385 11.438,-5.423 2.602,-0.548 5.877,-1.144 9.821,-1.788 5.886,-0.915 9.079,-2.258 9.572,-4.027 l 0.337,-1.197 c 0.406,-1.449 0.171,-2.551 -0.706,-3.304 -0.873,-0.754 -2.383,-1.129 -4.521,-1.129 -2.325,0 -4.304,0.476 -5.93,1.43 -1.63,0.953 -2.868,2.353 -3.722,4.201 l -15.015,0 c 2.371,-5.631 5.874,-9.82 10.507,-12.573 4.636,-2.751 10.511,-4.128 17.628,-4.128 4.428,0 8.014,0.535 10.754,1.606 2.739,1.069 4.66,2.69 5.763,4.86 0.753,1.559 1.074,3.417 0.958,5.573 -0.112,2.157 -0.838,5.617 -2.173,10.386 l -5.283,18.874 c -0.633,2.254 -0.926,4.03 -0.884,5.327 0.043,1.295 0.416,2.141 1.118,2.537 l -0.523,1.872 z M 512.532,67.424 c -1.479,0.794 -3.889,1.528 -7.229,2.201 -1.618,0.304 -2.856,0.564 -3.71,0.777 -2.115,0.551 -3.698,1.255 -4.748,2.107 -1.052,0.854 -1.777,2 -2.179,3.435 -0.497,1.771 -0.346,3.199 0.452,4.285 0.801,1.084 2.104,1.626 3.911,1.626 2.787,0 5.284,-0.803 7.496,-2.406 2.208,-1.603 3.677,-3.703 4.402,-6.298 l 1.605,-5.727 z"
id="path11"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 441.489,90.859 13.951,-49.816 15.682,0 -2.441,8.716 c 2.699,-3.419 5.567,-5.915 8.604,-7.489 3.039,-1.569 6.566,-2.386 10.587,-2.448 l -4.518,16.13 c -0.677,-0.089 -1.354,-0.161 -2.029,-0.206 -0.673,-0.046 -1.315,-0.068 -1.927,-0.068 -2.505,0 -4.682,0.374 -6.525,1.121 -1.843,0.749 -3.471,1.901 -4.886,3.46 -0.902,1.038 -1.758,2.527 -2.558,4.466 -0.803,1.939 -1.808,5.076 -3.026,9.414 l -4.681,16.72 -16.233,0 z"
id="path13"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 447.466,41.043 -13.947,49.816 -15.961,0 1.923,-6.863 c -2.729,2.77 -5.509,4.812 -8.336,6.121 -2.823,1.309 -5.84,1.962 -9.048,1.962 -5.497,0 -9.239,-1.41 -11.23,-4.23 -1.99,-2.818 -2.208,-7.005 -0.655,-12.554 l 9.591,-34.251 16.325,0 -7.806,27.876 c -1.145,4.097 -1.424,6.917 -0.83,8.461 0.586,1.542 2.146,2.315 4.68,2.315 2.839,0 5.169,-0.94 6.993,-2.818 1.82,-1.881 3.329,-4.945 4.517,-9.194 l 7.459,-26.64 16.325,0 z"
id="path15"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 361.923,50.894 2.757,-9.85 6.663,0 3.942,-14.073 16.322,0 -3.938,14.073 8.351,0 -2.759,9.85 -8.352,0 -6.042,21.585 c -0.924,3.3 -1.107,5.483 -0.551,6.553 0.559,1.068 2.014,1.603 4.369,1.603 l 1.223,-0.023 0.869,-0.068 -2.914,10.408 c -1.805,0.329 -3.551,0.586 -5.239,0.765 -1.686,0.18 -3.294,0.271 -4.819,0.271 -5.658,0 -9.141,-1.382 -10.447,-4.145 -1.304,-2.763 -0.694,-8.648 1.824,-17.655 l 5.402,-19.293 -6.661,0 z"
id="path17"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 350.752,90.859 -16.594,0 c 0.037,-0.791 0.106,-1.614 0.21,-2.466 l 0.353,-2.653 c -2.934,2.285 -5.846,3.974 -8.737,5.071 -2.891,1.096 -5.881,1.644 -8.966,1.644 -4.805,0 -8.234,-1.32 -10.292,-3.957 -2.057,-2.639 -2.462,-6.202 -1.204,-10.688 1.152,-4.121 3.184,-7.47 6.088,-10.048 2.909,-2.577 6.72,-4.385 11.442,-5.423 2.599,-0.548 5.872,-1.144 9.818,-1.788 5.885,-0.915 9.077,-2.258 9.573,-4.027 l 0.338,-1.197 c 0.403,-1.449 0.171,-2.551 -0.706,-3.304 -0.873,-0.754 -2.383,-1.129 -4.525,-1.129 -2.324,0 -4.3,0.476 -5.93,1.43 -1.626,0.953 -2.867,2.353 -3.722,4.201 l -15.01,0 c 2.371,-5.631 5.873,-9.82 10.509,-12.573 4.634,-2.751 10.507,-4.128 17.626,-4.128 4.428,0 8.01,0.535 10.749,1.606 2.74,1.069 4.665,2.69 5.765,4.86 0.755,1.559 1.077,3.417 0.961,5.573 -0.117,2.157 -0.837,5.617 -2.178,10.386 l -5.281,18.874 c -0.633,2.254 -0.928,4.03 -0.883,5.327 0.045,1.295 0.417,2.141 1.119,2.537 l -0.523,1.872 z M 339.394,67.424 c -1.48,0.794 -3.893,1.528 -7.233,2.201 -1.616,0.304 -2.853,0.564 -3.71,0.777 -2.115,0.551 -3.696,1.255 -4.746,2.107 -1.052,0.854 -1.777,2 -2.18,3.435 -0.498,1.771 -0.345,3.199 0.456,4.285 0.796,1.084 2.102,1.626 3.908,1.626 2.786,0 5.285,-0.803 7.493,-2.406 2.212,-1.603 3.68,-3.703 4.407,-6.298 l 1.605,-5.727 z"
id="path19"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 243.068,23.405 -18.893,67.455 -16.32,0 1.835,-6.548 c -2.596,2.712 -5.274,4.716 -8.033,6.011 -2.763,1.297 -5.747,1.946 -8.957,1.946 -6.232,0 -10.613,-2.406 -13.151,-7.215 -2.532,-4.812 -2.708,-11.11 -0.53,-18.896 2.199,-7.851 5.936,-14.246 11.217,-19.196 5.283,-4.947 10.963,-7.421 17.043,-7.421 3.268,0 5.996,0.659 8.181,1.975 2.181,1.316 3.737,3.259 4.668,5.83 l 6.706,-23.94 16.234,0 z m -50.367,42.038 c -1.25,4.457 -1.374,7.868 -0.373,10.234 1.003,2.366 3.062,3.552 6.172,3.552 3.112,0 5.798,-1.169 8.054,-3.505 2.259,-2.335 4.017,-5.764 5.282,-10.281 1.172,-4.181 1.238,-7.416 0.198,-9.706 -1.036,-2.292 -3.097,-3.437 -6.178,-3.437 -2.901,0 -5.534,1.177 -7.901,3.526 -2.367,2.352 -4.117,5.557 -5.254,9.617"
id="path21"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#3e3d3d;fill-rule:evenodd" /><path
d="m 131.769,90.859 13.949,-49.816 15.682,0 -2.441,8.716 c 2.701,-3.419 5.569,-5.915 8.604,-7.489 3.039,-1.569 13.384,-2.386 17.405,-2.448 l -4.517,16.13 c -0.675,-0.089 -1.351,-0.161 -2.03,-0.206 -0.671,-0.046 -1.315,-0.068 -1.929,-0.068 -2.503,0 -11.494,0.374 -13.339,1.121 -1.845,0.749 -3.471,1.901 -4.886,3.46 -0.902,1.038 -1.756,2.527 -2.556,4.466 -0.803,1.939 -1.812,5.076 -3.029,9.414 l -4.682,16.72 -16.231,0 z"
id="path23"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#3e3d3d;fill-rule:evenodd" /><path
d="m 114.704,75.192 15.667,0 c -2.994,5.465 -7.055,9.691 -12.186,12.683 -5.126,2.994 -10.866,4.487 -17.218,4.487 -7.727,0 -13.177,-2.345 -16.355,-7.033 -3.176,-4.689 -3.63,-11.081 -1.364,-19.175 2.309,-8.247 6.396,-14.773 12.263,-19.585 5.868,-4.809 12.634,-7.215 20.3,-7.215 7.909,0 13.439,2.446 16.586,7.336 3.151,4.891 3.52,11.644 1.106,20.264 l -0.528,1.813 -0.373,1.079 -33.689,0 c -0.978,3.502 -0.97,6.176 0.027,8.022 0.994,1.843 2.961,2.765 5.895,2.765 2.169,0 4.086,-0.457 5.748,-1.372 1.66,-0.914 3.034,-2.27 4.121,-4.069 m -13.672,-14.543 18.577,-0.043 c 0.834,-3.195 0.687,-5.692 -0.446,-7.489 -1.133,-1.794 -3.116,-2.693 -5.961,-2.693 -2.689,0 -5.083,0.883 -7.183,2.648 -2.1,1.765 -3.759,4.292 -4.987,7.577"
id="path25"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#3e3d3d;fill-rule:evenodd" /><path
d="m 279.482,91.578 -14.248,-41.467 -14.362,41.467 -16.14,0 21.281,-67.454 18.224,0 9.862,34.664 0.778,2.84 c 1.156,4.151 2.041,7.633 2.65,10.443 l 1.234,-4.857 c 0.487,-1.862 1.172,-4.304 2.057,-7.327 l 9.942,-35.763 18.222,0 -23.364,67.454 -16.136,0 z"
id="path27"
inkscape:connector-curvature="0"
style="fill:#a3d131" /></g><g
id="g29"><path
d="m 122.886,124.71 c -4.603,-5.205 -9.749,-8.869 -15.438,-10.989 -5.693,-2.117 -12.352,-3.179 -19.98,-3.179 -13.804,0 -23.794,2.605 -29.97,7.81 -6.175,5.208 -9.263,12.169 -9.263,20.888 0,4.359 0.755,8.023 2.271,10.989 1.513,2.969 3.874,5.48 7.083,7.538 3.207,2.061 7.294,3.786 12.26,5.177 4.964,1.393 10.898,2.814 17.8,4.268 7.021,1.453 13.378,3.028 19.072,4.723 5.69,1.697 10.535,3.846 14.531,6.448 3.996,2.605 7.083,5.844 9.263,9.718 2.18,3.876 3.27,8.658 3.27,14.349 0,5.449 -1.09,10.234 -3.27,14.35 -2.18,4.117 -5.268,7.568 -9.263,10.353 -3.996,2.787 -8.81,4.876 -14.44,6.267 -5.631,1.391 -11.897,2.089 -18.799,2.089 -10.293,0 -19.557,-1.604 -27.79,-4.813 -8.236,-3.207 -15.802,-8.143 -22.705,-14.803 l 3.633,-4.541 c 6.054,6.176 12.956,10.838 20.707,13.985 7.748,3.15 16.529,4.723 26.337,4.723 12.107,0 21.643,-2.208 28.607,-6.63 6.961,-4.418 10.444,-11.17 10.444,-20.252 0,-4.601 -0.849,-8.506 -2.543,-11.715 -1.697,-3.207 -4.268,-5.932 -7.719,-8.174 -3.451,-2.239 -7.782,-4.178 -12.987,-5.813 -5.208,-1.635 -11.383,-3.179 -18.527,-4.632 -7.024,-1.453 -13.259,-2.966 -18.708,-4.541 -5.449,-1.572 -10.021,-3.57 -13.713,-5.993 -3.695,-2.421 -6.479,-5.387 -8.355,-8.9 -1.879,-3.511 -2.815,-7.93 -2.815,-13.259 0,-5.69 1.09,-10.745 3.27,-15.167 2.18,-4.419 5.236,-8.111 9.172,-11.08 3.934,-2.966 8.688,-5.236 14.258,-6.812 5.568,-1.572 11.806,-2.361 18.708,-2.361 8.355,0 15.649,1.212 21.887,3.633 6.235,2.424 11.957,6.297 17.165,11.625 l -3.453,4.721 z"
id="path31"
inkscape:connector-curvature="0"
style="fill:#f7931e" /><path
d="m 142.321,234.599 55.58,-128.96 5.267,0 55.581,128.96 -6.902,0 -19.072,-44.5 -64.662,0 -19.072,44.5 -6.72,0 z m 58.304,-120.968 -30.696,71.019 60.847,0 -30.151,-71.019 z"
id="path33"
inkscape:connector-curvature="0"
style="fill:#f7931e" /><path
d="m 280.18,234.599 0,-128.96 6.175,0 0,123.148 79.192,0 0,5.813 -85.367,0 z"
id="path35"
inkscape:connector-curvature="0"
style="fill:#f7931e" /><path
d="m 387.523,234.599 0,-128.779 6.176,0 0,128.779 -6.176,0 z"
id="path37"
inkscape:connector-curvature="0"
style="fill:#f7931e" /><path
d="m 420.58,105.639 47.588,60.666 47.77,-60.666 7.266,0 -51.402,65.388 49.949,63.572 -7.266,0 -46.316,-58.85 -46.135,58.85 -7.447,0 49.949,-63.572 -51.402,-65.388 7.446,0 z"
id="path39"
inkscape:connector-curvature="0"
style="fill:#f7931e" /></g></g></svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1"
id="Capa_1" inkscape:version="0.91 r13725" sodipodi:docname="logo.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:ns="&#38;ns_sfw;" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 400 168.6"
style="enable-background:new 0 0 400 168.6;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#3D3D3F;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#8EBB27;}
.st2{fill:#8EBB27;}
.st3{fill:#F19300;}
</style>
<sodipodi:namedview bordercolor="#666666" borderopacity="1" fit-margin-bottom="0" fit-margin-left="0" fit-margin-right="0" fit-margin-top="0" gridtolerance="10" guidetolerance="10" id="namedview41" inkscape:current-layer="Capa_1" inkscape:cx="200" inkscape:cy="84.28212" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="1016" inkscape:window-maximized="1" inkscape:window-width="1920" inkscape:window-x="1920" inkscape:window-y="27" inkscape:zoom="3.09" objecttolerance="10" pagecolor="#ffffff" showgrid="false">
</sodipodi:namedview>
<g>
<g>
<path class="st0" d="M106.1,40L92.3,0h10.9l5.6,20.6l0.5,1.7c0.7,2.5,1.2,4.5,1.6,6.2c0.2-0.8,0.4-1.8,0.7-2.9
c0.3-1.1,0.7-2.6,1.2-4.3L118.7,0h10.8l-13.9,40H106.1z"/>
<path class="st1" d="M386.1,40h-9.8c0-0.5,0.1-1,0.1-1.5l0.2-1.6c-1.7,1.4-3.5,2.4-5.2,3c-1.7,0.6-3.5,1-5.3,1
c-2.8,0-4.9-0.8-6.1-2.3c-1.2-1.6-1.5-3.7-0.7-6.3c0.7-2.4,1.9-4.4,3.6-6c1.7-1.5,4-2.6,6.8-3.2c1.5-0.3,3.5-0.7,5.8-1.1
c3.5-0.5,5.4-1.3,5.7-2.4l0.2-0.7c0.2-0.9,0.1-1.5-0.4-2c-0.5-0.4-1.4-0.7-2.7-0.7c-1.4,0-2.6,0.3-3.5,0.8c-1,0.6-1.7,1.4-2.2,2.5
h-8.9c1.4-3.3,3.5-5.8,6.2-7.5c2.7-1.6,6.2-2.4,10.5-2.4c2.6,0,4.7,0.3,6.4,1c1.6,0.6,2.8,1.6,3.4,2.9c0.4,0.9,0.6,2,0.6,3.3
c-0.1,1.3-0.5,3.3-1.3,6.2l-3.1,11.2c-0.4,1.3-0.5,2.4-0.5,3.2c0,0.8,0.2,1.3,0.7,1.5L386.1,40z M379.4,26.1
c-0.9,0.5-2.3,0.9-4.3,1.3c-1,0.2-1.7,0.3-2.2,0.5c-1.3,0.3-2.2,0.7-2.8,1.2c-0.6,0.5-1.1,1.2-1.3,2c-0.3,1.1-0.2,1.9,0.3,2.5
c0.5,0.6,1.2,1,2.3,1c1.7,0,3.1-0.5,4.4-1.4c1.3-1,2.2-2.2,2.6-3.7L379.4,26.1z"/>
<path class="st1" d="M337.3,40l8.3-29.5h9.3l-1.4,5.2c1.6-2,3.3-3.5,5.1-4.4c1.8-0.9,3.9-1.4,6.3-1.5l-2.7,9.6
c-0.4-0.1-0.8-0.1-1.2-0.1c-0.4,0-0.8,0-1.1,0c-1.5,0-2.8,0.2-3.9,0.7c-1.1,0.4-2.1,1.1-2.9,2.1c-0.5,0.6-1,1.5-1.5,2.6
c-0.5,1.1-1.1,3-1.8,5.6l-2.8,9.9H337.3z"/>
<path class="st1" d="M340.8,10.5L332.5,40h-9.5l1.1-4.1c-1.6,1.6-3.3,2.9-4.9,3.6c-1.7,0.8-3.5,1.2-5.4,1.2
c-3.3,0-5.5-0.8-6.7-2.5c-1.2-1.7-1.3-4.2-0.4-7.4l5.7-20.3h9.7L317.6,27c-0.7,2.4-0.8,4.1-0.5,5c0.4,0.9,1.3,1.4,2.8,1.4
c1.7,0,3.1-0.6,4.1-1.7c1.1-1.1,2-2.9,2.7-5.5l4.4-15.8H340.8z"/>
<path class="st1" d="M290.1,16.3l1.6-5.8h4l2.3-8.3h9.7l-2.3,8.3h5l-1.6,5.8h-5l-3.6,12.8c-0.5,2-0.7,3.3-0.3,3.9
c0.3,0.6,1.2,1,2.6,1l0.7,0l0.5,0l-1.7,6.2c-1.1,0.2-2.1,0.3-3.1,0.5c-1,0.1-2,0.2-2.9,0.2c-3.4,0-5.4-0.8-6.2-2.5
c-0.8-1.6-0.4-5.1,1.1-10.5l3.2-11.4H290.1z"/>
<path class="st1" d="M283.5,40h-9.8c0-0.5,0.1-1,0.1-1.5L274,37c-1.7,1.4-3.5,2.4-5.2,3c-1.7,0.6-3.5,1-5.3,1
c-2.8,0-4.9-0.8-6.1-2.3c-1.2-1.6-1.5-3.7-0.7-6.3c0.7-2.4,1.9-4.4,3.6-6c1.7-1.5,4-2.6,6.8-3.2c1.5-0.3,3.5-0.7,5.8-1.1
c3.5-0.5,5.4-1.3,5.7-2.4l0.2-0.7c0.2-0.9,0.1-1.5-0.4-2c-0.5-0.4-1.4-0.7-2.7-0.7c-1.4,0-2.6,0.3-3.5,0.8c-1,0.6-1.7,1.4-2.2,2.5
H261c1.4-3.3,3.5-5.8,6.2-7.5c2.7-1.6,6.2-2.4,10.5-2.4c2.6,0,4.7,0.3,6.4,1c1.6,0.6,2.8,1.6,3.4,2.9c0.4,0.9,0.6,2,0.6,3.3
c-0.1,1.3-0.5,3.3-1.3,6.2l-3.1,11.2c-0.4,1.3-0.5,2.4-0.5,3.2c0,0.8,0.2,1.3,0.7,1.5L283.5,40z M276.7,26.1
c-0.9,0.5-2.3,0.9-4.3,1.3c-1,0.2-1.7,0.3-2.2,0.5c-1.3,0.3-2.2,0.7-2.8,1.2c-0.6,0.5-1.1,1.2-1.3,2c-0.3,1.1-0.2,1.9,0.3,2.5
c0.5,0.6,1.2,1,2.3,1c1.7,0,3.1-0.5,4.4-1.4c1.3-1,2.2-2.2,2.6-3.7L276.7,26.1z"/>
<path class="st0" d="M219.6,0l-11.2,40h-9.7l1.1-3.9c-1.5,1.6-3.1,2.8-4.8,3.6c-1.6,0.8-3.4,1.2-5.3,1.2c-3.7,0-6.3-1.4-7.8-4.3
c-1.5-2.9-1.6-6.6-0.3-11.2c1.3-4.7,3.5-8.4,6.7-11.4c3.1-2.9,6.5-4.4,10.1-4.4c1.9,0,3.6,0.4,4.8,1.2c1.3,0.8,2.2,1.9,2.8,3.5
L210,0H219.6z M189.8,24.9c-0.7,2.6-0.8,4.7-0.2,6.1c0.6,1.4,1.8,2.1,3.7,2.1c1.8,0,3.4-0.7,4.8-2.1c1.3-1.4,2.4-3.4,3.1-6.1
c0.7-2.5,0.7-4.4,0.1-5.8c-0.6-1.4-1.8-2-3.7-2c-1.7,0-3.3,0.7-4.7,2.1C191.5,20.6,190.4,22.5,189.8,24.9z"/>
<path class="st0" d="M153.6,40l8.3-29.5h9.3l-1.4,5.2c1.6-2,3.3-3.5,5.1-4.4c1.8-0.9,7.9-1.4,10.3-1.5l-2.7,9.6
c-0.4-0.1-0.8-0.1-1.2-0.1c-0.4,0-0.8,0-1.1,0c-1.5,0-6.8,0.2-7.9,0.7c-1.1,0.4-2.1,1.1-2.9,2.1c-0.5,0.6-1,1.5-1.5,2.6
c-0.5,1.1-1.1,3-1.8,5.6l-2.8,9.9H153.6z"/>
<path class="st0" d="M143.5,30.7h9.3c-1.8,3.2-4.2,5.7-7.2,7.5c-3,1.8-6.4,2.7-10.2,2.7c-4.6,0-7.8-1.4-9.7-4.2
c-1.9-2.8-2.2-6.6-0.8-11.4c1.4-4.9,3.8-8.8,7.3-11.6c3.5-2.9,7.5-4.3,12-4.3c4.7,0,8,1.5,9.8,4.3c1.9,2.9,2.1,6.9,0.7,12
l-0.3,1.1l-0.2,0.6h-20c-0.6,2.1-0.6,3.7,0,4.8c0.6,1.1,1.8,1.6,3.5,1.6c1.3,0,2.4-0.3,3.4-0.8C142.1,32.6,142.9,31.8,143.5,30.7z
M135.4,22.1l11,0c0.5-1.9,0.4-3.4-0.3-4.4c-0.7-1.1-1.8-1.6-3.5-1.6c-1.6,0-3,0.5-4.3,1.6C137.1,18.6,136.1,20.1,135.4,22.1z"/>
<path class="st2" d="M241.2,40.4l-8.4-24.6l-8.5,24.6h-9.6l12.6-40h10.8L244,21l0.5,1.7c0.7,2.5,1.2,4.5,1.6,6.2l0.7-2.9
c0.3-1.1,0.7-2.6,1.2-4.3l5.9-21.2h10.8l-13.9,40H241.2z"/>
</g>
<g>
<path class="st3" d="M106.1,54.4h4.8l48.9,113.9h-5.9L137,129H79.9l-16.8,39.3H57L106.1,54.4z M135.3,124.2l-26.8-62.7l-26.9,62.7
H135.3z"/>
<path class="st3" d="M178.1,168.3V54.4h5.6v108.7h69.8v5.1H178.1z"/>
<path class="st3" d="M271.1,168.3V54.4h5.6v113.9H271.1z"/>
<path class="st3" d="M300.2,54.4l42,53.6l42-53.6h6.4l-45.4,57.7l44.1,56.1H383l-40.7-52l-40.7,52h-6.7l44.1-56.1l-45.4-57.7
H300.2z"/>
<g>
<path class="st3" d="M5.8,168.3L5.3,163l0.2,2.7L5.3,163c0.4,0,10.4-1.1,18.9-11.8c10.5-13.1,14.1-35.2,10.5-63.9
C31,57.7,35.4,34.8,47.6,19.1C60.3,3,76.6,0.9,77.3,0.8l0.6,5.3c-0.1,0-11.9,1.6-22.4,12.1c-14,14-19.3,37.7-15.5,68.4
c3.8,30.7-0.1,53.6-11.8,68.1C18.3,167.1,6.3,168.2,5.8,168.3z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -6,7 +6,7 @@
save="post"
form="form">
</vn-watcher>
<form name="form" ng-submit="watcher.submitGo('clientCard.addresses.list')" margin-medium>
<form name="form" ng-submit="watcher.submitGo('clientCard.addresses.list')">
<vn-card pad-large>
<vn-title>Address</vn-title>
<vn-horizontal>

View File

@ -10,7 +10,7 @@
data="$ctrl.address"
form="form">
</vn-watcher>
<form name="form" ng-submit="$ctrl.submit()" margin-medium>
<form name="form" ng-submit="$ctrl.submit()">
<vn-card pad-large>
<vn-title>Address</vn-title>
<vn-horizontal>

View File

@ -1,5 +1,5 @@
<mg-ajax path="/client/api/Clients/{{index.params.id}}/listAddresses" options="mgIndex"></mg-ajax>
<vn-vertical pad-medium>
<vn-vertical>
<vn-card pad-large>
<vn-title vn-one>Addresses</vn-title>
<vn-horizontal ng-repeat="address in index.model.items track by address.id" class="pad-medium-top" style="align-items: center;">

View File

@ -5,7 +5,7 @@
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="watcher.submit()" margin-medium>
<form name="form" ng-submit="watcher.submit()">
<vn-card pad-large>
<vn-title>Basic data</vn-title>
<vn-horizontal>
@ -30,6 +30,7 @@
value-field="id"
select-fields="name"
label="Salesperson"
vn-acl="salesAssistant"
where="{or: [{firstName: {regexp: 'search'}}, {name: {regexp: 'search'}}]}">
</vn-autocomplete>
<vn-autocomplete vn-one

View File

@ -5,7 +5,7 @@
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="$ctrl.submit()" pad-medium>
<form name="form" ng-submit="$ctrl.submit()">
<vn-card pad-large>
<vn-title>Pay method</vn-title>
<vn-horizontal>

View File

@ -10,7 +10,7 @@
<vn-left-menu></vn-left-menu>
</vn-auto>
<vn-one>
<vn-vertical ui-view></vn-vertical>
<vn-vertical margin-medium ui-view></vn-vertical>
</vn-one>
</vn-horizontal>
</vn-main-block>

View File

@ -10,15 +10,19 @@
<vn-card pad-large>
<vn-title>Create client</vn-title>
<vn-horizontal>
<vn-textfield vn-one label="Name" field="$ctrl.client.name" vn-focus></vn-textfield>
<vn-textfield vn-two label="Business name" field="$ctrl.client.socialName"></vn-textfield>
<vn-textfield vn-one label="Tax number" field="$ctrl.client.fi"></vn-textfield>
<vn-check
vn-one
label="Is equalizated"
field="$ctrl.client.isEqualizated">
</vn-check>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Business name" field="$ctrl.client.socialName"></vn-textfield>
<vn-textfield vn-two label="Comercial Name" field="$ctrl.client.name" vn-focus></vn-textfield>
<vn-textfield vn-one label="Web user" field="$ctrl.client.userName"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Email" field="$ctrl.client.email" info="You can save multiple emails"></vn-textfield>
<vn-textfield vn-two label="Email" field="$ctrl.client.email" info="You can save multiple emails"></vn-textfield>
<vn-autocomplete vn-one
field="$ctrl.client.salesPersonFk"
url="/client/api/Clients/activeSalesPerson"
@ -29,6 +33,32 @@
where="{or: [{firstName: {regexp: 'search'}}, {name: {regexp: 'search'}}]}">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Postcode"
field="$ctrl.client.postcode">
</vn-textfield>
<vn-textfield
vn-two
label="Street"
field="$ctrl.client.street">
</vn-textfield>
<vn-textfield
vn-two
label="City"
field="$ctrl.client.city">
</vn-textfield>
<vn-autocomplete
vn-one
initial-data="$ctrl.client.province"
field="$ctrl.client.provinceFk"
url="/client/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit label="Create"></vn-submit>

View File

@ -5,7 +5,7 @@
form="form"
save="post">
</vn-watcher>
<form name="form" ng-submit="watcher.submitGo('clientCard.creditClassification.list')" pad-medium>
<form name="form" ng-submit="watcher.submitGo('clientCard.creditClassification.list')">
<vn-card pad-large>
<vn-title>New contract</vn-title>
<vn-horizontal>

View File

@ -1,4 +1,4 @@
<vn-vertical pad-medium>
<vn-vertical>
<vn-card pad-large>
<vn-title vn-one>Contract credit insurance</vn-title>
<vn-horizontal ng-repeat="classification in $ctrl.classifications track by classification.id" class="pad-medium-top" style="align-items: center;">

View File

@ -5,7 +5,7 @@
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="watcher.submitGo('clientCard.credit.list')" pad-medium>
<form name="form" ng-submit="watcher.submitGo('clientCard.credit.list')">
<vn-card pad-large>
<vn-title>Add credit</vn-title>
<vn-horizontal>

View File

@ -6,8 +6,7 @@
save="post">
</vn-watcher>
<form name="form"
ng-submit="watcher.submitGo('clientCard.creditInsurance.list', {classificationId: post.params.classificationId})"
pad-medium>
ng-submit="watcher.submitGo('clientCard.creditInsurance.list', {classificationId: post.params.classificationId})">
<vn-card pad-large>
<vn-title>New credit</vn-title>
<vn-horizontal>

View File

@ -1,5 +1,5 @@
<mg-ajax path="/client/api/CreditClassifications/{{index.params.classificationId}}/creditInsurances" options="vnIndex"></mg-ajax>
<vn-vertical pad-medium>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Requested credits</vn-title>

View File

@ -1,5 +1,5 @@
<mg-ajax path="/client/api/ClientCredits/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical pad-medium>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Credit</vn-title>

View File

@ -5,7 +5,7 @@
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="$ctrl.submit()" pad-medium>
<form name="form" ng-submit="$ctrl.submit()">
<vn-card pad-large>
<vn-title>Fiscal data</vn-title>
<vn-horizontal>

View File

@ -5,7 +5,7 @@
form="form"
save="post">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" pad-medium>
<form name="form" ng-submit="$ctrl.onSubmit()">
<vn-card pad-large>
<vn-title>Add Greuge</vn-title>
<vn-horizontal>

View File

@ -1,6 +1,6 @@
<mg-ajax path="/client/api/greuges/filter" options="vnIndexNonAuto"></mg-ajax>
<mg-ajax path="/client/api/greuges/{{edit.params.id}}/sumAmount" options="mgEdit"></mg-ajax>
<vn-vertical pad-medium>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Greuge</vn-title>

View File

@ -1,6 +1,6 @@
<mg-ajax path="/client/api/InvoiceOuts/filter" options="vnIndexNonAuto"></mg-ajax>
<mg-ajax path="/client/api/InvoiceOuts/{{edit.params.id}}/sumAmount" options="mgEdit"></mg-ajax>
<vn-vertical pad-medium>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Invoices</vn-title>

View File

@ -1,5 +1,5 @@
<mg-ajax path="/client/api/Mandates/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical pad-medium>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Mandate</vn-title>

View File

@ -6,7 +6,7 @@
save="post"
form="form">
</vn-watcher>
<form name="form" ng-submit="watcher.submitGo('clientCard.notes.list')" pad-medium>
<form name="form" ng-submit="watcher.submitGo('clientCard.notes.list')">
<vn-card pad-large>
<vn-title>New note</vn-title>
<vn-horizontal>

View File

@ -1,4 +1,4 @@
<vn-vertical pad-medium>
<vn-vertical>
<vn-card ng-show="$ctrl.observations.length" pad-large>
<vn-title>Notes</vn-title>
<vn-vertical

View File

@ -5,7 +5,7 @@
form="form"
save="post">
</vn-watcher>
<form pad-medium name="form" ng-submit="$ctrl.onSubmit()">
<form name="form" ng-submit="$ctrl.onSubmit()">
<vn-card pad-large>
<vn-title>Add recovery</vn-title>
<vn-horizontal>

View File

@ -1,5 +1,5 @@
<mg-ajax path="/client/api/Recoveries/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical pad-medium>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Recovery</vn-title>

View File

@ -1,4 +1,4 @@
<vn-vertical vn-one pad-medium>
<vn-vertical vn-one>
<vn-card class="summary">
<vn-vertical pad-medium>
<vn-auto>

View File

@ -2,5 +2,4 @@ User: Usuario
Enable web access: Habilitar acceso web
New password: Nueva contraseña
Repeat password: Repetir contraseña
Change password: Cambiar contraseña
Client must be checked to activate: No se puede activar un cliente si no esta verificado (036)
Change password: Cambiar contraseña

View File

@ -5,7 +5,7 @@
data="$ctrl.account"
form="form">
</vn-watcher>
<form name="form" ng-submit="watcher.submit()" pad-medium>
<form name="form" ng-submit="watcher.submit()">
<vn-card pad-large>
<vn-title>Web access</vn-title>
<vn-horizontal>
@ -13,8 +13,7 @@
vn-one
label="Enable web access"
field="$ctrl.account.active"
vn-acl="employee"
acl-conditional-to-employee="{{$ctrl.canEnableCheckBox}}">
vn-acl="employee">
</vn-check>
</vn-horizontal>
<vn-horizontal>
@ -23,7 +22,6 @@
vn-one
margin-medium-top
label="User"
info="Client must be checked to activate"
field="$ctrl.account.name">
</vn-textfield>
</vn-horizontal>

View File

@ -0,0 +1 @@
import './style.scss';

View File

@ -0,0 +1,16 @@
.vn-grid {
border-collapse: collapse;
td, th{
text-align: left;
padding: 10px;
}
& > thead, & > tbody {
border-bottom: 3px solid #9D9D9D;
}
& > tbody > tr{
border-bottom: 1px solid #9D9D9D;
}
td[number], th[number]{
text-align: right;
}
}

View File

@ -9,8 +9,8 @@
show="$ctrl.showDropDown"
selected="$ctrl.selected"
filter="true"
parent="$ctrl.element"
></vn-drop-down>
parent="$ctrl.element">
</vn-drop-down>
</div>
<div ng-if="$ctrl.findMore">
<vn-drop-down
@ -21,7 +21,7 @@
load-more="$ctrl.getItems()"
show-load-more="$ctrl.maxRow"
filter-action="$ctrl.findItems(search)"
parent="$ctrl.element"
></vn-drop-down>
parent="$ctrl.element">
</vn-drop-down>
</div>
</div>

View File

@ -16,6 +16,7 @@ import './drop-down/drop-down';
import './menu/menu';
import './column-header/column-header';
import './grid-header/grid-header';
import './grid/grid';
import './multi-check/multi-check';
import './date-picker/date-picker';
import './button/button';

View File

@ -32,14 +32,21 @@ export default class Popover extends Component {
this.content = this.element.querySelector('.content');
}
set child(value) {
this.content.appendChild(value);
}
/**
* @type {HTMLElement} The popover child.
*/
get child() {
return this.content.firstChild;
}
set child(value) {
this.content.innerHTML = '';
this.content.appendChild(value);
}
/**
* @type {Boolean} Wether to show or hide the popover.
*/
get shown() {
return this._shown;
}

View File

@ -1,10 +1,10 @@
<form name="form" ng-submit="$ctrl.submit()">
<vn-card pad-large>
<vn-title>Item Barcodes</vn-title>
<vn-title>Item barcode</vn-title>
<vn-horizontal ng-repeat="barcode in $ctrl.barcodes track by $index">
<vn-textfield
vn-three
label="code"
label="Code"
model="barcode.code"
vn-acl="buyer, replenisher">
</vn-textfield>

View File

@ -16,16 +16,20 @@
<vn-autocomplete vn-one
url="/item/api/ItemTypes"
label="Type"
show-field="name"
select-fields=["code","name"]
value-field="id"
field="$ctrl.item.typeFk">
field="$ctrl.item.typeFk"
where="{or: [{code: {regexp: 'search'}}, {name: {regexp: 'search'}}]}">
<tpl-item>{{code}} : {{name}}</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one
url="/item/api/Intrastats"
label="Intrastat"
value-field="id"
show-field="description"
field="$ctrl.item.intrastatFk">
value-field="id"
field="$ctrl.item.intrastatFk"
where="{or: [{id: {regexp: 'search'}}, {description: {regexp: 'search'}}]}">
<tpl-item>{{id}} : {{description}}</tpl-item>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
@ -36,12 +40,6 @@
value-field="id"
field="$ctrl.item.originFk">
</vn-autocomplete>
<vn-autocomplete vn-one
url="/item/api/Expences"
label="Expence"
field="$ctrl.item.expenceFk"
initial-data="$ctrl.item.expence">
</vn-autocomplete>
</vn-horizontal>
</vn-card>
<vn-button-bar>

View File

@ -26,4 +26,12 @@ Do you want to clone this item?: ¿Desea clonar este artículo?
All it's properties will be copied: Todas sus propiedades serán copiadas
Yes, clone: Si, clonar
Value: Valor
Priority: Prioridad
Priority: Prioridad
Item tax: Tasas del artículo
Country: País
Class: Clase
Item niches: Nichos del artículo
Warehouse: Almacén
Code: Código
Botanical: Botánico
Species: Especie

View File

@ -5,7 +5,7 @@
</vn-watcher>
<form name="form" ng-submit="$ctrl.submit()">
<vn-card pad-large>
<vn-title>Item Niches</vn-title>
<vn-title>Item niches</vn-title>
<vn-horizontal ng-repeat="itemNiche in $ctrl.niches track by $index">
<vn-autocomplete
ng-if="!itemNiche.id"
@ -27,7 +27,7 @@
</vn-textfield>
<vn-textfield
vn-two
label="code"
label="Code"
model="itemNiche.code"
rule="itemNiche.code"
vn-acl="buyer,replenisher">

View File

@ -2,7 +2,7 @@
"module": "ticket",
"name": "Tickets",
"icon": "icon-ticket",
"validations": false,
"validations": true,
"routes": [
{
"url": "/ticket",
@ -47,9 +47,9 @@
}
},
{
"url": "/observations",
"state": "ticket.card.observations",
"component": "vn-ticket-observations",
"url": "/observation",
"state": "ticket.card.observation",
"component": "vn-ticket-observation",
"params": {
"ticket": "$ctrl.ticket"
},
@ -59,15 +59,45 @@
}
},
{
"url" : "/package",
"abstract": true,
"state": "ticket.card.package",
"component": "ui-view"
"url": "/volume",
"state": "ticket.card.volume",
"component": "vn-ticket-volume",
"params": {
"ticket": "$ctrl.ticket"
},
"menu": {
"description": "Volume",
"icon": "icon-volume"
}
},
{
"url": "/list",
"state": "ticket.card.package.list",
"component": "vn-ticket-package-list",
"url": "/expedition",
"state": "ticket.card.expedition",
"component": "vn-ticket-expedition",
"params": {
"ticket": "$ctrl.ticket"
},
"menu": {
"description": "Expedition",
"icon": "icon-volum"
}
},
{
"url": "/mana",
"state": "ticket.card.mana",
"component": "vn-ticket-mana",
"params": {
"ticket": "$ctrl.ticket"
},
"menu": {
"description": "Mana",
"icon": "icon-sms"
}
},
{
"url" : "/package",
"state": "ticket.card.package",
"component": "vn-ticket-package",
"params": {
"ticket": "$ctrl.ticket"
},
@ -77,16 +107,36 @@
}
},
{
"url" : "/review",
"state": "ticket.card.review",
"component": "vn-ticket-review",
"url" : "/tracking",
"state": "ticket.card.tracking",
"component": "vn-ticket-tracking",
"params": {
"ticket": "$ctrl.ticket"
},
"menu": {
"description": "Review",
"description": "Tracking",
"icon": "remove_red_eye"
}
},
{
"url": "/create",
"state": "ticket.card.tracking.create",
"component": "vn-ticket-tracking-create",
"params": {
"client": "$ctrl.client"
}
},
{
"url" : "/sale",
"state": "ticket.card.sale",
"component": "vn-ticket-sale",
"params": {
"ticket": "$ctrl.ticket"
},
"menu": {
"description": "Sale",
"icon": "icon-lines"
}
}
]
}

View File

@ -0,0 +1,42 @@
<mg-ajax path="/ticket/api/Expeditions/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Expedition</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h text="Delete"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="itemFk" text="Item"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="name" text="Name" order-locked></vn-column-header>
<vn-column-header vn-one pad-medium-h field="packageFk" text="Package type"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="counter" text="Counter"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="checked" text="Checked"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="worker" text="Worker"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="created" text="Created" default-order="DESC"></vn-column-header>
</vn-grid-header>
<vn-one class="list list-content">
<vn-horizontal
vn-one class="list list-element text-center"
pad-small-bottom
ng-repeat="expedition in index.model.instances track by expedition.id">
<vn-none pad-medium-h style="color:#FFA410;">
<i
pointer
class="material-icons"
vn-tooltip="delete expedition"
ng-click="$ctrl.deleteExpedition(expedition)">delete</i>
</vn-none>
<vn-one pad-medium-h>{{expedition.itemFk}}</vn-one>
<vn-one pad-medium-h>{{expedition.item.name}}</vn-one>
<vn-one pad-medium-h>{{expedition.package.name}}</vn-one>
<vn-one pad-medium-h>{{expedition.counter}}</vn-one>
<vn-one pad-medium-h>{{expedition.checked}}</vn-one>
<vn-one pad-medium-h>{{expedition.worker.firstName}} {{expedition.worker.name}}</vn-one>
<vn-one pad-medium-h>{{expedition.created | date:'dd/MM/yyyy'}}</vn-one>
</vn-horizontal>
</vn-one>
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
<vn-horizontal vn-one class="list list-footer"></vn-horizontal>
<vn-paging vn-one margin-large-top index="index" total="index.model.count"></vn-paging>
</vn-vertical>
</vn-card>
</vn-vertical>

View File

@ -0,0 +1,22 @@
import ngModule from '../module';
import FilterTicketList from '../filter-ticket-list';
class Controller extends FilterTicketList {
constructor($scope, $timeout, $stateParams, $http) {
super($scope, $timeout, $stateParams);
this.params = $stateParams;
this.$http = $http;
}
deleteExpedition(expedition) {
this.$http.delete(`/ticket/api/Expeditions/${expedition.id}`, this.params).then(
() => this.$.index.accept()
);
}
}
Controller.$inject = ['$scope', '$timeout', '$state', '$http'];
ngModule.component('vnTicketExpedition', {
template: require('./ticket-expedition.html'),
controller: Controller
});

View File

@ -0,0 +1,8 @@
<vn-vertical style="text-align:center">
<vn-one>{{::$ctrl.sale.concept}}</vn-one>
<vn-one>
<vn-one ng-repeat="fetchedTag in $ctrl.sale.itemTag track by $index">
<vn-label>{{::fetchedTag.tag.name}} </vn-label>{{::fetchedTag.value}}
</vn-one>
</vn-one>
</vn-vertical>

View File

@ -0,0 +1,12 @@
import ngModule from '../module';
class Controller {}
Controller.$inject = [];
ngModule.component('vnFetchedTags', {
template: require('./fetched-tags.html'),
controller: Controller,
bindings: {
sale: '<'
}
});

View File

@ -0,0 +1,9 @@
import FilterList from 'core/src/lib/filter-list';
export default class FilterTicketList extends FilterList {
constructor($scope, $timeout, $state) {
super($scope, $timeout, $state);
this.modelName = 'ticketFk';
}
}
FilterTicketList.$inject = ['$scope', '$timeout', '$state'];

View File

@ -1,6 +1,21 @@
Tickets: Tickets
Amount: Importe
Basic data: Datos básicos
Description: Descripción
Discount: Descuento
Item: Articulo
Delete: Borrar
delete expedition: borrar expedición
Expedition: Expedición
Name: Nombre
Package type: Tipo de porte
Counter: Contador
Checked: Comprobado
Worker: Trabajador
Notes: Notas
Observation type: Tipo de observación
Description: Descripción
Price: Precio
Quantity: Cantidad
Sale: Lineas del pedido
Some fields are invalid: Algunos campos no son válidos
The observation type must be unique: El tipo de observación debe ser único
Some fields are invalid: Algunos campos no son válidos
Tickets: Tickets

View File

@ -1,6 +1,6 @@
<vn-watcher
vn-id="watcher"
url="/client/api/Addresses"
url="/ticket/api/Observation"
id-field="id"
data="$ctrl.address"
form="form">
@ -31,7 +31,8 @@
vn-two
margin-large-right
label="Description"
model="ticketObservation.description">
model="ticketObservation.description"
rule="ticketObservation.description">
</vn-textfield>
<vn-auto pad-medium-top>
<vn-icon

View File

@ -1,6 +1,6 @@
import ngModule from '../module';
class TicketObservations {
class Controller {
constructor($stateParams, $scope, $http, $translate, vnApp) {
this.params = $stateParams;
this.$scope = $scope;
@ -116,7 +116,7 @@ class TicketObservations {
canSubmit = observationsObj.update.length > 0 || observationsObj.create.length > 0 || observationsObj.delete.length > 0;
if (canSubmit) {
return this.$http.post(`/ticket/api/TicketObservations/crudTicketObservations`, observationsObj).then(() => {
return this.$http.post(`/ticket/api/TicketObservations/crudTicketObservation`, observationsObj).then(() => {
this.getObservations();
this._unsetDirtyForm();
});
@ -129,11 +129,11 @@ class TicketObservations {
}
}
TicketObservations.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp'];
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp'];
ngModule.component('vnTicketObservations', {
template: require('./ticket-observations.html'),
controller: TicketObservations,
ngModule.component('vnTicketObservation', {
template: require('./ticket-observation.html'),
controller: Controller,
bindings: {
ticket: '<'
}

View File

@ -1,7 +1,7 @@
import './ticket-observations.js';
import './ticket-observation.js';
describe('ticket', () => {
describe('Component vnTicketObservations', () => {
describe('Component vnTicketObservation', () => {
let $componentController;
let $state;
let controller;
@ -15,7 +15,7 @@ describe('ticket', () => {
$componentController = _$componentController_;
$state = _$state_;
$httpBackend = _$httpBackend_;
controller = $componentController('vnTicketObservations', {$state: $state});
controller = $componentController('vnTicketObservation', {$state: $state});
}));
describe('add / remove observation', () => {
@ -24,10 +24,10 @@ describe('ticket', () => {
spyOn(controller, '_setIconAdd').and.callThrough();
controller.addObservation();
expect(controller._setIconAdd).toHaveBeenCalledWith();
expect(controller.ticketObservations.length).toEqual(1);
expect(controller.ticketObservations[0].id).toBe(undefined);
expect(controller.ticketObservations[0].showAddIcon).toBeTruthy();
expect(controller._setIconAdd).toHaveBeenCalledWith();
});
it('should remove an observation that occupies the position in the index given and call _setIconAdd()', () => {
@ -42,11 +42,11 @@ describe('ticket', () => {
controller.removeObservation(index);
expect(controller._setIconAdd).toHaveBeenCalledWith();
expect(controller.ticketObservations.length).toEqual(2);
expect(controller.ticketObservations[0].showAddIcon).toBeFalsy();
expect(controller.ticketObservations[1].showAddIcon).toBeTruthy();
expect(controller.ticketObservations[index]).toBe(undefined);
expect(controller._setIconAdd).toHaveBeenCalledWith();
});
});
@ -70,16 +70,33 @@ describe('ticket', () => {
describe('get Observations()', () => {
it('should perform a GET query to receive the ticket observations', () => {
let res = [{id: 1, observationTypeFk: 1, description: 'one'}];
let response = [{id: 1, observationTypeFk: 1, description: 'one'}];
spyOn(controller, 'setOldObservations');
$httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond(res);
$httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond(response);
$httpBackend.expectGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`);
controller.getObservations();
$httpBackend.flush();
expect(controller.setOldObservations).toHaveBeenCalledWith(jasmine.any(Object));
});
});
describe('submit()', () => {
it("should return an error message 'Some fields are invalid'", () => {
controller.$scope.form = {};
controller.$scope.form.$invalid = true;
spyOn(controller.vnApp, 'showMessage').and.callThrough();
controller.ticketObservations = [
{id: 1, observationTypeFk: 1, description: 'one', itemFk: 1},
{observationTypeFk: 1, description: 'one', itemFk: 1}
];
controller.oldObservations = {1: {id: 1, observationTypeFk: 1, description: 'one', itemFk: 1}};
controller.submit();
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Some fields are invalid');
});
it("should return an error message 'The observation type must be unique'", () => {
controller.$scope.form = {};
spyOn(controller.vnApp, 'showMessage').and.callThrough();
@ -100,7 +117,7 @@ describe('ticket', () => {
controller.removedObservations = [1];
$httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
$httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).respond('ok!');
$httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservation`).respond('ok!');
controller.submit();
$httpBackend.flush();
});
@ -111,7 +128,7 @@ describe('ticket', () => {
controller.oldObservations = {1: {id: 1, observationTypeFk: 1, description: 'one'}};
$httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
$httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).respond('ok!');
$httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservation`).respond('ok!');
controller.submit();
$httpBackend.flush();
});
@ -121,7 +138,7 @@ describe('ticket', () => {
controller.ticketObservations = [{observationTypeFk: 2, description: 'two'}];
$httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
$httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).respond('ok!');
$httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservation`).respond('ok!');
controller.submit();
$httpBackend.flush();
});

View File

@ -1,56 +0,0 @@
<mg-ajax
path="/ticket/api/Tickets/{{index.params.id}}/packages"
options="mgIndex">
</mg-ajax>
<vn-card pad-large>
<vn-title>Packages</vn-title>
<vn-one>
<vn-horizontal ng-repeat="package in index.model track by package.id">
<vn-autocomplete vn-one
margin-large-right
url="/ticket/api/Packagings/listPackaging"
label="Package"
show-field="name"
value-field="packagingFk"
field="package.packagingFk">
<tpl-item>{{id}} : {{name}}</tpl-item>
</vn-autocomplete>
<vn-textfield
vn-one
margin-large-right
label="Quantity"
model="package.quantity">
</vn-textfield>
<vn-textfield
vn-one
margin-large-right
label="Added"
model="package.created | date: 'dd/MM/yyyy'"
disabled="true"
ng-readonly="true">
</vn-textfield>
<vn-auto pad-medium-top>
<vn-icon
pointer
medium-grey
vn-tooltip="Remove package"
tooltip-position = "left"
icon="remove_circle_outline"
ng-click="$ctrl.removePackage($index)">
</vn-icon>
</vn-one>
</vn-horizontal>
</vn-one>
<vn-one>
<vn-icon
pointer
margin-medium-left
vn-tooltip="Add package"
tooltip-position = "right"
orange
icon="add_circle"
ng-click="$ctrl.addPackage()">
</vn-icon>
</vn-one>
</vn-card>

View File

@ -1,19 +0,0 @@
import ngModule from '../../module';
class Controller {
construct($http, $scope) {
this.$http = $http;
this.$ = $scope;
}
}
Controller.$inject = ['$http', '$scope'];
ngModule.component('vnTicketPackageList', {
template: require('./package-list.html'),
controller: Controller,
bindings: {
ticket: '<'
}
});

View File

@ -0,0 +1,68 @@
<mg-ajax
path="/ticket/api/Tickets/{{index.params.id}}/packages"
options="mgIndex" actions="$ctrl.getPackages()">
</mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.packages"
form="form">
</vn-watcher>
<form name="form" ng-submit="$ctrl.submit()">
<vn-card pad-large>
<vn-title>Packages</vn-title>
<vn-one>
<vn-horizontal ng-repeat="package in index.model track by $index">
<vn-autocomplete vn-one
margin-large-right
url="/ticket/api/Packagings/listPackaging"
label="Package"
show-field="name"
value-field="packagingFk"
field="package.packagingFk">
<tpl-item>{{id}} : {{name}}</tpl-item>
</vn-autocomplete>
<vn-textfield
vn-one
margin-large-right
label="Quantity"
model="package.quantity"
rule="TicketPackaging.quantity">
</vn-textfield>
<vn-textfield
vn-one
margin-large-right
label="Added"
model="package.created | date: 'dd/MM/yyyy'"
disabled="true"
ng-readonly="true">
</vn-textfield>
<vn-auto pad-medium-top>
<vn-icon
pointer
medium-grey
vn-tooltip="Remove package"
tooltip-position = "left"
icon="remove_circle_outline"
ng-click="$ctrl.removePackage($index)">
</vn-icon>
</vn-one>
</vn-horizontal>
</vn-one>
<vn-one>
<vn-icon
pointer
margin-medium-left
vn-tooltip="Add package"
tooltip-position = "right"
orange
icon="add_circle"
ng-click="$ctrl.addPackage()">
</vn-icon>
</vn-one>
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
</vn-button-bar>
</form>

View File

@ -0,0 +1,73 @@
import ngModule from '../module';
class Controller {
constructor($http, $scope, $translate, vnApp) {
this.$http = $http;
this.$ = $scope;
this.$translate = $translate;
this.vnApp = vnApp;
this.removedPackages = [];
this.updatedPackages = [];
}
submit() {
let query = `/ticket/api/TicketPackagings/crudTicketPackaging`;
let packagesObj = {
delete: this.removedPackages,
create: [],
update: []
};
this.packages.forEach(item => {
if (typeof item.id === 'undefined')
packagesObj.create.push(item);
if (typeof item.id !== 'undefined' && angular.equals(item, this.oldPackages[item.id]))
packagesObj.update.push(item);
});
this.$http.post(query, packagesObj).then(res => {
this.$.index.accept();
});
}
removePackage(index) {
if (this.packages[index] && this.packages[index].id)
this.removedPackages.push(this.packages[index].id);
this.packages.splice(index, 1);
}
addPackage() {
let data = {
packagingFk: null,
quantity: null,
created: Date.now(),
ticketFk: this.ticket.id
};
this.packages.push(data);
}
getPackages() {
this.packages = this.$.index.model;
this.setOldPackages();
}
setOldPackages() {
this.oldPackages = [];
this.packages.forEach(item => {
this.oldPackages[item.id] = item;
});
}
}
Controller.$inject = ['$http', '$scope'];
ngModule.component('vnTicketPackage', {
template: require('./package.html'),
controller: Controller,
bindings: {
ticket: '<'
}
});

View File

@ -0,0 +1,59 @@
import './package.js';
describe('Ticket', () => {
describe('Component vnTicketPackage', () => {
let $componentController;
let controller;
let $httpBackend;
let $scope;
beforeEach(() => {
angular.mock.module('ticket');
});
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_, $rootScope) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$scope = {
index: {
accept: function() {}
}
};
controller = $componentController('vnTicketPackage', {$scope: $scope});
}));
describe('removePackage()', () => {
it('should push a package to removedPackages in the controller', () => {
controller.packages = [{id: 1}, {id: 2}];
controller.removePackage(0);
expect(controller.removedPackages).toEqual([1]);
});
});
describe('submit()', () => {
it('should perform a post', () => {
spyOn(angular, 'equals').and.returnValue(true);
let query = '/ticket/api/TicketPackagings/crudTicketPackaging';
controller.removedPackages = [];
controller.oldPackages = [
{id: 1, quantity: 5, ticketFk: 1}
];
controller.packages = [
{quantity: 5, ticketFk: 1},
{id: 1, quantity: 25, ticketFk: 1}
];
let packagesObj = {
delete: controller.removedPackages,
create: [],
update: []
};
$httpBackend.whenPOST(query, packagesObj).respond('omg YEAH');
$httpBackend.expectPOST(query, packagesObj);
controller.submit();
$httpBackend.flush();
});
});
});
});

View File

@ -1,4 +0,0 @@
date : Fecha
Employee : Empleado
State: Estado
Review: Revision

View File

@ -1,23 +0,0 @@
<mg-ajax path="" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical pad-medium>
<vn-card pad-large>
<vn-vertical>
<vn-title>Review</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h field="date" text="date"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="employee" text="Employee" default-order="ASC"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="state" text="State" order-locked></vn-column-header>
</vn-grid-header>
<vn-one class="list list-content">
</vn-horizontal>
</vn-one>
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
<vn-horizontal vn-one class="list list-footer"></vn-horizontal>
<vn-paging vn-one margin-large-top index="index" total="index.model.count"></vn-paging>
</vn-vertical>
</vn-card>
</vn-vertical>
<a ui-sref="clientCard.ticket.create" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -1,18 +0,0 @@
import ngModule from '../module';
class ticketReview {
construct($http, $scope) {
this.$http = $http;
this.$ = $scope;
}
}
ticketReview.$inject = ['$http', '$scope'];
ngModule.component('vnTicketReview', {
template: require('./review.html'),
controller: ticketReview,
bindings: {
ticket: '<'
}
});

View File

@ -0,0 +1,30 @@
<mg-ajax path="/ticket/api/sales/filter" options="vnIndex"></mg-ajax>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Sale</vn-title>
<table class="vn-grid">
<thead>
<tr>
<th number translate>Item</th>
<th translate style="text-align:center">Description</th>
<th number translate>Quantity</th>
<th number translate>Price</th>
<th number translate>Discount</th>
<th number translate>Amount</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="sale in index.model.instances track by sale.id">
<td number>{{::sale.itemFk}}</td>
<td><vn-fetched-tags sale="sale"/></td>
<td number>{{::sale.quantity}}</td>
<td number>{{::sale.price | currency:'€':2}}</td>
<td number>{{::sale.discount}} %</td>
<td number>{{::sale.quantity * sale.price | currency:'€':2}}</td>
</tr>
</tbody>
</table>
</vn-vertical>
</vn-card>
</vn-vertical>

View File

@ -0,0 +1,7 @@
import ngModule from '../module';
import FilterTicketList from '../filter-ticket-list';
ngModule.component('vnTicketSale', {
template: require('./sale.html'),
controller: FilterTicketList
});

View File

@ -5,6 +5,10 @@ import './create/ticket-create';
import './card/ticket-card';
import './summary/ticket-summary';
import './data/ticket-data';
import './notes/ticket-observations';
import './package/list/package-list';
import './review/review';
import './note/ticket-observation';
import './expedition/ticket-expedition';
import './volume/ticket-volume';
import './package/package';
import './sale/sale';
import './tracking/tracking';
import './fetched-tags/fetched-tags';

View File

@ -0,0 +1,5 @@
Date : Fecha
Employee : Empleado
State: Estado
Tracking: Revisión
Created : Añadido

View File

@ -0,0 +1,31 @@
<mg-ajax path="/ticket/api/TicketTrackings/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical pad-medium>
<vn-card pad-large>
<vn-vertical>
<vn-title>Tracking</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h field="state.name" text="State"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="employee" text="Employee"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="created" text="Created" default-order="ASC"></vn-column-header>
</vn-grid-header>
<vn-one class="list list-content">
<vn-horizontal
vn-one class="list list-element text-center"
pad-small-bottom
ng-repeat="ticket in index.model.instances track by ticket.id">
<vn-one pad-medium-h>{{::ticket.state.name}}</vn-one>
<vn-two pad-medium-h>{{::ticket.worker.firstName}} {{::ticket.worker.name}}</vn-two>
<vn-two pad-medium-h>{{::ticket.created | date:'dd/MM/yyyy HH:mm' }}</vn-two>
</vn-horizontal>
</vn-one>
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
<vn-horizontal vn-one class="list list-footer"></vn-horizontal>
<vn-paging vn-one margin-large-top index="index" total="index.model.count"></vn-paging>
</vn-vertical>
</vn-card>
</vn-vertical>
<a ui-sref="ticket.card.tracking.create" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -0,0 +1,7 @@
import ngModule from '../module';
import FilterTicketList from '../filter-ticket-list';
ngModule.component('vnTicketTracking', {
template: require('./tracking.html'),
controller: FilterTicketList
});

View File

@ -0,0 +1,10 @@
<form name="form" ng-submit="$ctrl.submit()">
<vn-card pad-large>
<vn-one margin-medium-top>
<vn-title>Volumes</vn-title>
</vn-one>
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
</vn-button-bar>
</form>

View File

@ -0,0 +1,32 @@
import ngModule from '../module';
class Controller {
constructor($stateParams, $scope, $http, $translate, vnApp) {
this.params = $stateParams;
this.$scope = $scope;
this.$http = $http;
this.$translate = $translate;
this.vnApp = vnApp;
this.ticketVolumes = [];
this.oldVolumes = {};
this.removedVolumes = [];
}
_getTicketVolumes(ticketFk) {
this.$http.get(`/tcket/api/Volumes/${ticketFk}/getVolumes`)
.then(response => {
this.ticketVolumes = response.data;
});
}
}
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp'];
ngModule.component('vnTicketVolume', {
template: require('./ticket-volume.html'),
controller: Controller,
bindings: {
ticket: '<'
}
});

View File

@ -0,0 +1,143 @@
// import './ticket-observations.js';
// describe('ticket', () => {
// describe('Component vnTicketObservations', () => {
// let $componentController;
// let $state;
// let controller;
// let $httpBackend;
// beforeEach(() => {
// angular.mock.module('ticket');
// });
// beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_) => {
// $componentController = _$componentController_;
// $state = _$state_;
// $httpBackend = _$httpBackend_;
// controller = $componentController('vnTicketObservations', {$state: $state});
// }));
// describe('add / remove observation', () => {
// it('should add one empty observation into controller observations collection and call _setIconAdd()', () => {
// controller.ticketObservations = [];
// spyOn(controller, '_setIconAdd').and.callThrough();
// controller.addObservation();
// expect(controller._setIconAdd).toHaveBeenCalledWith();
// expect(controller.ticketObservations.length).toEqual(1);
// expect(controller.ticketObservations[0].id).toBe(undefined);
// expect(controller.ticketObservations[0].showAddIcon).toBeTruthy();
// });
// it('should remove an observation that occupies the position in the index given and call _setIconAdd()', () => {
// let index = 2;
// controller.ticketObservations = [
// {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: false},
// {id: 2, observationTypeFk: 2, description: 'two', showAddIcon: false},
// {id: 3, observationTypeFk: 3, description: 'three', showAddIcon: true}
// ];
// spyOn(controller, '_setIconAdd').and.callThrough();
// controller.removeObservation(index);
// expect(controller._setIconAdd).toHaveBeenCalledWith();
// expect(controller.ticketObservations.length).toEqual(2);
// expect(controller.ticketObservations[0].showAddIcon).toBeFalsy();
// expect(controller.ticketObservations[1].showAddIcon).toBeTruthy();
// expect(controller.ticketObservations[index]).toBe(undefined);
// });
// });
// describe('_equalObservations()', () => {
// it('should return true if two observations are equals independent of control attributes', () => {
// let observationOne = {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: true};
// let observationTwo = {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: false};
// let equals = controller._equalObservations(observationOne, observationTwo);
// expect(equals).toBeTruthy();
// });
// it('should return false if two observations aint equals independent of control attributes', () => {
// let observationOne = {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: true};
// let observationTwo = {id: 1, observationTypeFk: 1, description: 'two', showAddIcon: true};
// let equals = controller._equalObservations(observationOne, observationTwo);
// expect(equals).toBeFalsy();
// });
// });
// describe('get Observations()', () => {
// it('should perform a GET query to receive the ticket observations', () => {
// let res = [{id: 1, observationTypeFk: 1, description: 'one'}];
// $httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond(res);
// $httpBackend.expectGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`);
// controller.getObservations();
// $httpBackend.flush();
// });
// });
// describe('submit()', () => {
// it("should return an error message 'The observation type must be unique'", () => {
// controller.$scope.form = {};
// spyOn(controller.vnApp, 'showMessage').and.callThrough();
// controller.ticketObservations = [
// {id: 1, observationTypeFk: 1, description: 'one', itemFk: 1},
// {observationTypeFk: 1, description: 'one', itemFk: 1}
// ];
// controller.oldObservations = {1: {id: 1, observationTypeFk: 1, description: 'one', itemFk: 1}};
// controller.submit();
// expect(controller.vnApp.showMessage).toHaveBeenCalledWith('The observation type must be unique');
// });
// it("should perfom a query to delete observations", () => {
// controller.$scope.form = {$setPristine: () => {}};
// controller.oldObservations = {1: {id: 1, observationTypeFk: 1, description: 'one'}};
// controller.ticketObservations = [];
// controller.removedObservations = [1];
// $httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
// $httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).respond('ok!');
// controller.submit();
// $httpBackend.flush();
// });
// it("should perfom a query to update observations", () => {
// controller.$scope.form = {$setPristine: () => {}};
// controller.ticketObservations = [{id: 1, observationTypeFk: 1, description: 'number one!'}];
// controller.oldObservations = {1: {id: 1, observationTypeFk: 1, description: 'one'}};
// $httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
// $httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).respond('ok!');
// controller.submit();
// $httpBackend.flush();
// });
// it("should perfom a query to create new observation", () => {
// controller.$scope.form = {$setPristine: () => {}};
// controller.ticketObservations = [{observationTypeFk: 2, description: 'two'}];
// $httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
// $httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).respond('ok!');
// controller.submit();
// $httpBackend.flush();
// });
// it("should return a message 'No changes to save' when there are no changes to apply", () => {
// controller.$scope.form = {$setPristine: () => {}};
// spyOn(controller.vnApp, 'showMessage').and.callThrough();
// controller.oldObservations = [
// {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: false},
// {id: 2, observationTypeFk: 2, description: 'two', showAddIcon: true}
// ];
// controller.ticketObservations = [];
// controller.submit();
// expect(controller.vnApp.showMessage).toHaveBeenCalledWith('No changes to save');
// });
// });
// });
// });

View File

@ -57,9 +57,10 @@ export default {
provinceFifthOption: `${components.vnAutocomplete}[field="$ctrl.client.provinceFk"] vn-drop-down ul > li:nth-child(5)`,
countryInput: `${components.vnAutocomplete}[field="$ctrl.client.countryFk"] input`,
countryThirdOption: `${components.vnAutocomplete}[field="$ctrl.client.countryFk"] vn-drop-down ul > li:nth-child(3)`,
activeCheckboxLabel: `${components.vnCheck}[label='Active'] > label`,
activeCheckboxLabel: `${components.vnCheck}[label="Active"] > label`,
frozenCheckboxLabel: `${components.vnCheck}[label="Frozen"] > label`,
invoiceByAddressCheckboxInput: `${components.vnCheck}[label='Invoice by address'] > label > input`,
verifiedDataCheckboxInput: `${components.vnCheck}[label='Verified data'] > label > input`,
verifiedDataCheckboxInput: `${components.vnCheck}[label="Verified data"] > label > input`,
hasToInvoiceCheckboxLabel: `${components.vnCheck}[label='Has to invoice'] > label`,
invoiceByMailCheckboxLabel: `${components.vnCheck}[label='Invoice by mail'] > label`,
viesCheckboxInput: `${components.vnCheck}[label='Vies'] > label > input`,
@ -166,8 +167,6 @@ export default {
intrastatSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] vn-drop-down ul > li:nth-child(2)`,
originSelect: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] input`,
originSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] vn-drop-down ul > li:nth-child(2)`,
expenceSelect: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] input`,
expenceSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] vn-drop-down ul > li:nth-child(2)`,
createButton: `${components.vnSubmit}`
},
@ -241,15 +240,15 @@ export default {
firstWarehouseSelect: `${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
firstWarehouseDisabled: `vn-horizontal:nth-child(2) > vn-textfield[label="Warehouse"] > div > input`,
firstWarehouseSelectSecondOption: `${components.vnAutocomplete}[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(2)`,
firstCodeInput: `vn-horizontal:nth-child(2) > vn-textfield[label="code"] > div > input`,
firstCodeInput: `vn-horizontal:nth-child(2) > vn-textfield[label="Code"] > div > input`,
secondWarehouseSelect: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
secondWarehouseDisabled: `vn-horizontal:nth-child(3) > vn-textfield[label="Warehouse"] > div > input`,
secondCodeInput: `vn-horizontal:nth-child(3) > vn-textfield[label="code"] > div > input`,
secondCodeInput: `vn-horizontal:nth-child(3) > vn-textfield[label="Code"] > div > input`,
secondNicheRemoveButton: `vn-horizontal:nth-child(3) > vn-one > ${components.vnIcon}[icon="remove_circle_outline"]`,
thirdWarehouseSelect: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
thirdWarehouseDisabled: `vn-horizontal:nth-child(4) > vn-textfield[label="Warehouse"] > div > input`,
thirdWarehouseSelectFourthOption: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(4)`,
thirdCodeInput: `vn-horizontal:nth-child(4) > vn-textfield[label="code"] > div > input`,
thirdCodeInput: `vn-horizontal:nth-child(4) > vn-textfield[label="Code"] > div > input`,
submitNichesButton: `${components.vnSubmit}`
},
itemBotanical: {
@ -278,7 +277,7 @@ export default {
searchButton: `${components.vnSearchBar} > vn-icon-button > button`
},
ticketNotes: {
notesButton: `${components.vnMenuItem}[ui-sref="ticket.card.observations"]`,
notesButton: `${components.vnMenuItem}[ui-sref="ticket.card.observation"]`,
firstNoteRemoveButton: `${components.vnIcon}[icon="remove_circle_outline"]`,
addNoteButton: `${components.vnIcon}[icon="add_circle"]`,
firstNoteSelect: `${components.vnAutocomplete}[field="ticketObservation.observationTypeFk"] input`,
@ -287,8 +286,13 @@ export default {
firstDescriptionInput: `vn-textfield[label="Description"] > div > input`,
submitNotesButton: `${components.vnSubmit}`
},
ticketExpedition: {
expeditionButton: `${components.vnMenuItem}[ui-sref="ticket.card.expedition"]`,
secondExpeditionRemoveButton: `body > vn-app > vn-vertical > vn-vertical > ui-view > vn-ticket-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-ticket-expedition > vn-vertical > vn-card > div > vn-vertical > vn-one > vn-horizontal:nth-child(2) > vn-none > i`,
secondExpeditionText: `body > vn-app > vn-vertical > vn-vertical > ui-view > vn-ticket-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-ticket-expedition > vn-vertical > vn-card > div > vn-vertical > vn-one > vn-horizontal:nth-child(2)`
},
ticketPackages: {
packagesButton: `${components.vnMenuItem}[ui-sref="ticket.card.package.list"]`,
packagesButton: `${components.vnMenuItem}[ui-sref="ticket.card.package"]`,
firstPackageSelect: `${components.vnAutocomplete}[label="Package"] input`
}
};

View File

@ -99,6 +99,7 @@ describe('Edit fiscalData path', () => {
.waitToClick(selectors.clientFiscalData.provinceInput)
.waitToClick(selectors.clientFiscalData.provinceFifthOption)
.waitToClick(selectors.clientFiscalData.activeCheckboxLabel)
.waitToClick(selectors.clientFiscalData.frozenCheckboxLabel)
.waitToClick(selectors.clientFiscalData.invoiceByAddressCheckboxInput)
.waitToClick(selectors.clientFiscalData.verifiedDataCheckboxInput)
.waitToClick(selectors.clientFiscalData.hasToInvoiceCheckboxLabel)
@ -227,6 +228,16 @@ describe('Edit fiscalData path', () => {
});
});
it('should confirm frozen checkbox is unchecked', () => {
return nightmare
.evaluate(selector => {
return document.querySelector(selector).checked;
}, selectors.clientFiscalData.frozenCheckboxLabel)
.then(value => {
expect(value).toBeFalsy();
});
});
it('should confirm invoice by address checkbox is unchecked', () => {
return nightmare
.evaluate(selector => {

View File

@ -112,7 +112,7 @@ describe('edit item basic data path', () => {
return nightmare
.getInputValue(selectors.itemBasicData.expenceSelect)
.then(result => {
expect(result).toEqual('loan');
expect(result).toEqual('Adquisición mercancia Extracomunitaria');
});
});
});

View File

@ -51,8 +51,6 @@ describe('Item', () => {
.waitToClick(selectors.itemCreateView.intrastatSelectOptionOne)
.waitToClick(selectors.itemCreateView.originSelect)
.waitToClick(selectors.itemCreateView.originSelectOptionOne)
.waitToClick(selectors.itemCreateView.expenceSelect)
.waitToClick(selectors.itemCreateView.expenceSelectOptionOne)
.click(selectors.itemCreateView.createButton)
.waitForSnackbar()
.then(result => {
@ -81,11 +79,6 @@ describe('Item', () => {
})
.then(result => {
expect(result).toBe('Spain');
return nightmare
.getInputValue(selectors.itemBasicData.expenceSelect);
})
.then(result => {
expect(result).toBe('loan');
});
});
});

View File

@ -1,7 +1,7 @@
import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/helpers';
describe('create item niche path', () => {
describe('create ticket notes path', () => {
const nightmare = createNightmare();
beforeAll(() => {
@ -36,10 +36,10 @@ describe('create item niche path', () => {
.waitForTextInElement(selectors.ticketsIndex.searchResult, '1')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketNotes.notesButton)
.waitForURL('observations')
.waitForURL('observation')
.url()
.then(url => {
expect(url).toContain('observations');
expect(url).toContain('observation');
});
});

View File

@ -0,0 +1,59 @@
import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/helpers';
describe('delete ticket expeditions path', () => {
const nightmare = createNightmare();
beforeAll(() => {
return nightmare
.waitForLogin('developer');
});
it('should access to the tickets index by clicking the tickets button', () => {
return nightmare
.click(selectors.moduleAccessView.ticketsSectionButton)
.wait(selectors.ticketsIndex.createTicketButton)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/ticket/list');
});
});
it('should search for the ticket with id 1', () => {
return nightmare
.wait(selectors.ticketsIndex.searchTicketInput)
.type(selectors.ticketsIndex.searchTicketInput, '1')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countSearchResults(selectors.ticketsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should click on the search result to access to the ticket expeditions`, () => {
return nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResult, '1')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketExpedition.expeditionButton)
.waitForURL('expedition')
.url()
.then(url => {
expect(url).toContain('expedition');
});
});
it(`should delete a former expedition and confirm the remaining expedition is the expected one`, () => {
return nightmare
.waitToClick(selectors.ticketExpedition.secondExpeditionRemoveButton)
.click(selectors.ticketPackages.packagesButton)
.wait(selectors.ticketPackages.firstPackageSelect)
.click(selectors.ticketExpedition.expeditionButton)
.wait(selectors.ticketExpedition.secondExpeditionText)
.getInnerText(selectors.ticketExpedition.secondExpeditionText)
.then(value => {
expect(value).toContain('Iron Patriot');
expect(value).toContain('root');
});
});
});

3934
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@
"fs-extra": "^5.0.0",
"material-design-lite": "^1.3.0",
"mg-crud": "^1.1.2",
"npm": "^5.7.1",
"oclazyload": "^0.6.3",
"require-yaml": "0.0.1",
"validator": "^6.2.1"

File diff suppressed because one or more lines are too long

View File

@ -384,24 +384,22 @@ INSERT INTO `vn`.`intrastat`(`id`, `description`, `taxClassFk`, `taxCodeFk`)
(05080000, 'Coral y materiales similares' , 2, 2),
(06021010, 'Plantas vivas: Esqueje/injerto, Vid', 1, 1);
INSERT INTO `vn`.`expence`(`id`, `taxTypeFk`, `name`, `isWithheld`)
VALUES
(1, 1, 'bail', 0),
(2, 1, 'loan', 1);
INSERT INTO `vn`.`item`(`id`, `name`,`typeFk`,`size`,`inkFk`,`category`,`stems`,`originFk`,`description`,`producerFk`,`intrastatFk`,`isOnOffer`,`expenceFk`,`isBargain`,`comment`,`relevancy`,`image`,`taxClassFk`)
VALUES
(1, 'Gem of Time', 2, 70, 'AMA', 'EXT', 1, 1, 'One of the infinity gems', 1, 06021010, 0, 1, 0, NULL, 0, 66540, 1),
(2, 'Gem of Mind', 2, 70, 'AZL', 'EXT', 1, 2, 'One of the infinity gems', 1, 06021010, 0, 1, 0, NULL, 0, 65540, 1),
(3, 'Iron Patriot', 1, 60, 'AMR', 'EXT', 1, 3, 'Rhodeys armor', 1, 05080000, 0, 1, 0, NULL, 0, 61692, 1),
(4, 'Mark I', 1, 60, 'AMR', 'EXT', 1, 1, 'Iron Mans first armor', 1, 05080000, 1, 2, 0, NULL, 0, 66090, 2),
(5, 'Mjolnir', 3, 30, 'AZR', 'EXT', 1, 2, 'Thors hammer!', 2, 06021010, 1, 2, 0, NULL, 0, 67350, 2);
(1, 'Gem of Time', 2, 70, 'AMA', 'EXT', 1, 1, 'One of the infinity gems', 1, 06021010, 0, 2000000000, 0, NULL, 0, 66540, 1),
(2, 'Gem of Mind', 2, 70, 'AZL', 'EXT', 1, 2, 'One of the infinity gems', 1, 06021010, 0, 2000000000, 0, NULL, 0, 65540, 1),
(3, 'Iron Patriot', 1, 60, 'AMR', 'EXT', 1, 3, 'Rhodeys armor', 1, 05080000, 0, 4751000000, 0, NULL, 0, 61692, 1),
(4, 'Mark I', 1, 60, 'AMR', 'EXT', 1, 1, 'Iron Mans first armor', 1, 05080000, 1, 4751000000, 0, NULL, 0, 66090, 2),
(5, 'Mjolnir', 3, 30, 'AZR', 'EXT', 1, 2, 'Thors hammer!', 2, 06021010, 1, 4751000000, 0, NULL, 0, 67350, 2);
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`)
VALUES
( 1, 1, 1, 0, CURDATE(), 1, 0, 2, 1),
( 2, 1, 1, 1, CURDATE(), 2, 1, 0, 2),
( 3, 2, 2, 2, CURDATE(), 3, 2, 0, NULL);
( 3, 2, 1, 2, CURDATE(), 3, 2, 0, NULL),
( 4, 1, 1, 0, CURDATE(), 1, 0, 2, 1),
( 5, 1, 1, 1, CURDATE(), 2, 1, 0, 2),
( 6, 2, 1, 2, CURDATE(), 3, 2, 0, NULL);
INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPackageReturnable`, `created`, `itemFk`, `price`)
VALUES
@ -509,4 +507,19 @@ INSERT INTO `vn`.`recovery`(`id`, `clientFk`, `started`, `finished`, `amount`, `
( 1, 101, CURDATE(), date_add(CURDATE(),INTERVAL 1 MONTH), 50, 7),
( 2, 102, CURDATE(), date_add(CURDATE(),INTERVAL 3 MONTH), 100, 1),
( 3, 102, CURDATE(), date_add(CURDATE(),INTERVAL 1 MONTH), 50, 7),
( 4, 103, CURDATE(), NULL, 50, 7);
( 4, 103, CURDATE(), NULL, 50, 7);
INSERT INTO `bi`.`rotacion`(`Id_Article`, `warehouse_id`, `total`, `rotacion`, `cm3`, `almacenaje`, `manipulacion`, `auxiliar`, `mermas`)
VALUES
( 1, 1, 0, 0.0000, 1500, 0.0015, 0.0250, 0.0085, 0.0000),
( 1, 2, 0, 0.0000, 100, 0.0060, 0.0200, 0.0080, 0.0000),
( 2, 1, 10, 3.5000, 0, 0.0000, 0.0000, 0.0080, 0.0000),
( 3, 1, 50, 5.5000, 100, 0.0000, 0.0000, 0.0080, 0.0000);
INSERT INTO `vn`.`annualAverageInvoiced`(`clientFk`, `invoiced`)
VALUES
( 101, 0),
( 102, 100),
( 103, 1000),
( 104, 500),
( 105, 5000);

View File

@ -12,3 +12,4 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `pri
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Expedition', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Expedition', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Expedition', '*', 'WRITE', 'ALLOW', 'ROLE', 'production');
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('AnnualAverageInvoiced', '*', 'READ', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,10 @@
USE `vn`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`annualAverageInvoiced` AS
SELECT
`e`.`Id_Cliente` AS `clientFk`, `e`.`Consumo` AS `invoiced`
FROM
`bi`.`facturacion_media_anual` `e`;

View File

@ -5,6 +5,8 @@ echo USE `salix`; >> 02-dumpedFixtures.sql
mysqldump --defaults-file=connect.ini --no-create-info salix ACL >> 02-dumpedFixtures.sql
echo USE `vn`; >> 02-dumpedFixtures.sql
mysqldump --defaults-file=connect.ini --no-create-info vn cplusInvoiceType477 cplusSubjectOp cplusTaxBreak >> 02-dumpedFixtures.sql
echo USE `vn2008`; >> 02-dumpedFixtures.sql
mysqldump --defaults-file=connect.ini --no-create-info vn2008 accion_dits Gastos >> 02-dumpedFixtures.sql

View File

@ -5,5 +5,6 @@
"The default consignee can not be unchecked": "The default consignee can not be unchecked",
"Unable to default a disabled consignee": "Unable to default a disabled consignee",
"El método de pago seleccionado requiere que se especifique el IBAN": "El método de pago seleccionado requiere que se especifique el IBAN",
"Ya existe un usuario con ese nombre": "Ya existe un usuario con ese nombre"
"Ya existe un usuario con ese nombre": "Ya existe un usuario con ese nombre",
"Quantity cannot be zero": "Quantity cannot be zero"
}

View File

@ -8,7 +8,6 @@
"can't be blank": "can't be blank",
"DNI Incorrecto": "DNI Incorrecto",
"Ya existe un usuario con ese nombre": "Ya existe un usuario con ese nombre",
"ValidationError: The `Item` instance is not valid. Details: `originFk` Cannot be blank (value: undefined).": "ValidationError: The `Item` instance is not valid. Details: `originFk` Cannot be blank (value: undefined).",
"Error: ER_NO_REFERENCED_ROW_2: Cannot add or update a child row: a foreign key constraint fails (`vn2008`.`Articles`, CONSTRAINT `Articles_ibfk_5` FOREIGN KEY (`tipo_id`) REFERENCES `Tipos` (`tipo_id`) ON UPDATE CASCADE)": "Error: ER_NO_REFERENCED_ROW_2: Cannot add or update a child row: a foreign key constraint fails (`vn2008`.`Articles`, CONSTRAINT `Articles_ibfk_5` FOREIGN KEY (`tipo_id`) REFERENCES `Tipos` (`tipo_id`) ON UPDATE CASCADE)",
"Error: ER_NO_REFERENCED_ROW_2: Cannot add or update a child row: a foreign key constraint fails (`vn2008`.`Articles`, CONSTRAINT `expenceFk` FOREIGN KEY (`expenceFk`) REFERENCES `Gastos` (`Id_Gasto`) ON UPDATE CASCADE)": "Error: ER_NO_REFERENCED_ROW_2: Cannot add or update a child row: a foreign key constraint fails (`vn2008`.`Articles`, CONSTRAINT `expenceFk` FOREIGN KEY (`expenceFk`) REFERENCES `Gastos` (`Id_Gasto`) ON UPDATE CASCADE)"
"is invalid": "is invalid",
"Quantity cannot be zero": "La cantidad no puede ser cero"
}

View File

@ -35,7 +35,12 @@ module.exports = function(Self) {
fi: data.fi,
socialName: data.socialName,
email: data.email,
salesPersonFk: data.salesPersonFk
salesPersonFk: data.salesPersonFk,
postcode: data.postcode,
street: data.street,
city: data.city,
provinceFk: data.provinceFk,
isEqualizated: data.isEqualizated
};
newClient = await Self.create(client, {transaction});
await transaction.commit();

View File

@ -1,12 +1,11 @@
const app = require('../../../../../client/server/server');
const catchErrors = require('../../../../../../services/utils/jasmineHelpers').catchErrors;
const restoreFixtures = require('../../../../../../services/db/testing_fixtures');
describe('Client Create', () => {
let sqlStatements = {deletes: `
DELETE FROM vn.address WHERE nickname = "Wade";
DELETE FROM vn.client WHERE name = "Wade";
DELETE FROM account.user WHERE name = "Deadpool";
DELETE FROM vn.address WHERE nickname = 'Wade';
DELETE FROM vn.client WHERE name = 'Wade';
DELETE FROM account.user WHERE name = 'Deadpool';
`, inserts: ``, updates: ``};
beforeAll(() => {
@ -17,70 +16,50 @@ describe('Client Create', () => {
restoreFixtures(sqlStatements);
});
let newAccountData = {
active: true,
name: 'Wade',
let newAccount = {
userName: 'Deadpool',
email: 'Deadpool@marvel.com',
fi: '16195279J',
socialName: 'Deadpool Marvel',
salesPersonFk: 1
name: 'Wade',
socialName: 'Deadpool Marvel'
};
it('should find Charles Xavier', done => {
app.models.Account.findOne({where: {name: 'CharlesXavier'}})
.then(account => {
expect(account.name).toEqual('CharlesXavier');
done();
});
it(`should not find Deadpool as he's not created yet`, async() => {
let account = await app.models.Account.findOne({where: {name: newAccount.userName}});
let client = await app.models.Client.findOne({where: {name: newAccount.name}});
expect(account).toEqual(null);
expect(client).toEqual(null);
});
it(`should not find Deadpool as he's not created yet`, done => {
app.models.Account.findOne({where: {name: newAccountData.userName}})
.then(account => {
expect(account).toEqual(null);
app.models.Client.findOne({where: {name: newAccountData.name}})
.then(client => {
expect(client).toEqual(null);
done();
});
})
.catch(catchErrors(done));
it('should create a new account', async() => {
let client = await app.models.Client.createWithUser(newAccount);
let account = await app.models.Account.findOne({where: {name: newAccount.userName}});
expect(account.name).toEqual(newAccount.userName);
client = await app.models.Client.findOne({where: {name: newAccount.name}});
expect(client.id).toEqual(account.id);
expect(client.name).toEqual(newAccount.name);
expect(client.email).toEqual(newAccount.email);
expect(client.fi).toEqual(newAccount.fi);
expect(client.socialName).toEqual(newAccount.socialName);
});
it('should find an existing account', async() => {
let account = await app.models.Account.findOne({where: {name: newAccount.userName}});
expect(account.name).toEqual(newAccount.userName);
});
it('should not be able to create a user if exists', async() => {
let client = await app.models.Client.findOne({where: {name: 'Charles Xavier'}});
let account = await app.models.Account.findOne({where: {id: client.id}});
let formerAccountData = {
name: client.name,
userName: account.name,
email: client.email,
fi: client.fi,
socialName: client.socialName
};
try {
let client = await app.models.Client.createWithUser(formerAccountData);
let client = await app.models.Client.createWithUser(newAccount);
expect(client).toBeNull();
} catch (err) {
expect(err.details.codes.name[0]).toEqual('uniqueness');
}
});
it('should create a new account', async() => {
let client = await app.models.Client.createWithUser(newAccountData);
let account = await app.models.Account.findOne({where: {name: newAccountData.userName}});
expect(account.name).toEqual(newAccountData.userName);
client = await app.models.Client.findOne({where: {name: newAccountData.name}});
expect(client.id).toEqual(account.id);
expect(client.name).toEqual(newAccountData.name);
expect(client.email).toEqual(newAccountData.email);
expect(client.fi).toEqual(newAccountData.fi);
expect(client.socialName).toEqual(newAccountData.socialName);
});
});

View File

@ -0,0 +1,26 @@
module.exports = Self => {
Self.remoteMethod('getVolumes', {
description: 'Returns the volumes of a ticket',
accessType: 'READ',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'ticket id',
http: {source: 'path'}
}],
returns: {
type: 'object'
},
http: {
path: `/:id/getVolumes`,
verb: 'GET'
}
});
Self.getVolumes = async ticketFk => {
let query = `SELECT vn.ticketVolume(?) AS ticketVolumes`;
let response = await Self.rawSql(query, [ticketFk]);
return response[0];
};
};

View File

@ -0,0 +1,16 @@
// const getDebt = require('../getDebt');
// describe('client getDebt()', () => {
// it('should call the getDebt method', done => {
// let clientFk = 109;
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'rawSql']);
// self.rawSql.and.returnValue(Promise.resolve([{debt: 100}]));
// getDebt(self);
// self.getDebt(clientFk)
// .then(result => {
// expect(result.debt).toEqual(100);
// done();
// });
// });
// });

View File

@ -44,11 +44,11 @@ module.exports = function(Self) {
allowBlank: true
});
Self.validateAsync('fi', fiIsValid, {
Self.validateAsync('fi', tinIsValid, {
message: 'DNI Incorrecto'
});
let validateDni = require('../validations/validateDni');
async function fiIsValid(err, done) {
let validateTin = require('../validations/validateTin');
async function tinIsValid(err, done) {
let filter = {
fields: ['code'],
where: {id: this.countryFk}
@ -56,7 +56,7 @@ module.exports = function(Self) {
let country = await Self.app.models.Country.findOne(filter);
let code = country ? country.code.toLowerCase() : null;
if (!validateDni(this.fi, code))
if (!validateTin(this.fi, code))
err();
done();
}

View File

@ -12,6 +12,9 @@
"id": true,
"description": "Identifier"
},
"code": {
"type": "String"
},
"name": {
"type": "String"
},

View File

@ -3,4 +3,5 @@ module.exports = function(Self) {
require('../methods/ticket/change-time.js')(Self);
require('../methods/ticket/change-worker.js')(Self);
require('../methods/ticket/filter.js')(Self);
require('../methods/ticket/get-volume.js')(Self);
};

View File

@ -1,26 +1,26 @@
const validateDni = require('../validateDni');
const validateDni = require('../validateTin');
describe('DNI validation', () => {
it('should return true for any DNI when no country is passed', () => {
describe('TIN validation', () => {
it('should return true for any TIN when no country is passed', () => {
let isValid = validateDni('Pepinillos');
expect(isValid).toBeTruthy();
});
describe('Spanish', () => {
it('should return true for valid spanish DNI', () => {
it('should return true for valid spanish TIN', () => {
let isValid = validateDni('20849756A', 'es');
expect(isValid).toBeTruthy();
});
it('should return false for spanish DNI with exceeded digits', () => {
it('should return false for spanish TIN with exceeded digits', () => {
let isValid = validateDni('208497563239A', 'es');
expect(isValid).toBeFalsy();
});
it('should return false for spanish DNI with invalid letter', () => {
it('should return false for spanish TIN with invalid letter', () => {
let isValid = validateDni('20243746E', 'es');
expect(isValid).toBeFalsy();
@ -40,19 +40,19 @@ describe('DNI validation', () => {
});
describe('French', () => {
it('should return true for valid french DNI', () => {
let isValid = validateDni('1B123456789', 'fr');
it('should return true for valid french TIN', () => {
let isValid = validateDni('012345678', 'fr');
expect(isValid).toBeTruthy();
});
it('should return false for french DNI with exceeded digits', () => {
let isValid = validateDni('1B12345678910', 'fr');
it('should return false for french TIN with exceeded digits', () => {
let isValid = validateDni('1B123456789101234', 'fr');
expect(isValid).toBeFalsy();
});
it('should return false for french DNI with bad syntax', () => {
it('should return false for french TIN with bad syntax', () => {
let isValid = validateDni('1B12345678A', 'fr');
expect(isValid).toBeFalsy();
@ -60,19 +60,19 @@ describe('DNI validation', () => {
});
describe('Italian', () => {
it('should return true for valid italian DNI', () => {
it('should return true for valid italian TIN', () => {
let isValid = validateDni('12345678911', 'it');
expect(isValid).toBeTruthy();
});
it('should return false for italian DNI with exceeded digits', () => {
it('should return false for italian TIN with exceeded digits', () => {
let isValid = validateDni('123456789112', 'it');
expect(isValid).toBeFalsy();
});
it('should return false for italian DNI with bad syntax', () => {
it('should return false for italian TIN with bad syntax', () => {
let isValid = validateDni('1234567891A', 'it');
expect(isValid).toBeFalsy();
@ -80,19 +80,19 @@ describe('DNI validation', () => {
});
describe('Portuguese', () => {
it('should return true for valid portuguese DNI', () => {
it('should return true for valid portuguese TIN', () => {
let isValid = validateDni('123456789', 'pt');
expect(isValid).toBeTruthy();
});
it('should return false for portuguese DNI with exceeded digits', () => {
it('should return false for portuguese TIN with exceeded digits', () => {
let isValid = validateDni('12345678910', 'pt');
expect(isValid).toBeFalsy();
});
it('should return false for portuguese DNI with bad syntax', () => {
it('should return false for portuguese TIN with bad syntax', () => {
let isValid = validateDni('12345678A', 'pt');
expect(isValid).toBeFalsy();

View File

@ -1,24 +1,24 @@
module.exports = function(fi, country) {
if (fi == null || country == null)
module.exports = function(tin, country) {
if (tin == null || country == null)
return true;
if (typeof fi != 'string' || typeof country != 'string')
if (typeof tin != 'string' || typeof country != 'string')
return false;
fi = fi.toUpperCase();
tin = tin.toUpperCase();
country = country.toLowerCase();
let len = fi.length;
let len = tin.length;
let validators = {
es: {
regExp: /^[A-Z0-9]\d{7}[A-Z0-9]$/,
validate: () => {
let isCif = /[A-W]/.test(fi.charAt(0));
let lastDigit = fi.charAt(len - 1);
let isCif = /[A-W]/.test(tin.charAt(0));
let lastDigit = tin.charAt(len - 1);
let computedDigit;
if (isCif) {
let numbers = fi.substring(1, 8)
let numbers = tin.substring(1, 8)
.split('')
.map(x => parseInt(x));
@ -41,8 +41,8 @@ module.exports = function(fi, country) {
computedDigit = index == -1 ? control.toString() : index;
} else {
// Foreign NIF
let index = 'XYZ'.indexOf(fi.charAt(0));
let nif = index == -1 ? fi : index.toString() + fi.substring(1);
let index = 'XYZ'.indexOf(tin.charAt(0));
let nif = index == -1 ? tin : index.toString() + tin.substring(1);
let rest = parseInt(nif.substring(0, 8)) % 23;
computedDigit = 'TRWAGMYFPDXBNJZSQVHLCKE'.charAt(rest);
@ -52,10 +52,10 @@ module.exports = function(fi, country) {
}
},
fr: {
regExp: /^[A-Z0-9]{2}\d{9}$/
regExp: /^\d{1,13}$/
},
it: {
regExp: /^\d{11}$/
regExp: /^(\d{11}|[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z])$/
},
pt: {
regExp: /^\d{9}$/
@ -67,6 +67,6 @@ module.exports = function(fi, country) {
if (!validator)
return true;
return validator.regExp.test(fi)
return validator.regExp.test(tin)
&& (!validator.validate || validator.validate());
};

View File

@ -0,0 +1,22 @@
module.exports = Self => {
Self.installMethod('filter', filterParams);
function filterParams(params) {
return {
where: {
ticketFk: params.ticketFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'created DESC',
include: [{
relation: 'item',
scope: {fields: ['name']}
},
{
relation: 'worker',
scope: {fields: ['firstName', 'name']}
}]
};
}
};

View File

@ -0,0 +1,3 @@
module.exports = Self => {
Self.installCrudModel('crudTicketObservation');
};

View File

@ -0,0 +1,3 @@
module.exports = Self => {
Self.installCrudModel('crudTicketPackaging');
};

View File

@ -0,0 +1,26 @@
module.exports = Self => {
Self.installMethod('filter', filterParams);
function filterParams(params) {
return {
where: {
ticketFk: params.ticketFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'concept ASC',
include: [{
relation: "itemTag",
scope: {
fields: ["id", "value", "priority", "tagFk"],
include: {
relation: "tag",
scope: {
fields: ["name"]
}
}
}
}]
};
}
};

View File

@ -1,3 +0,0 @@
module.exports = Self => {
Self.installCrudModel('crudTicketObservations');
};

View File

@ -0,0 +1,28 @@
module.exports = Self => {
Self.installMethod('filter', filterParams);
function filterParams(params) {
return {
where: {
ticketFk: params.ticketFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'created DESC',
include: [
{
relation: "worker",
scope: {
fields: ["firstName", "name"]
}
},
{
relation: "state",
scope: {
fields: ["name"]
}
}
]
};
}
};

View File

@ -0,0 +1,24 @@
{
"name": "AnnualAverageInvoiced",
"base": "VnModel",
"options": {
"mysql": {
"table": "annualAverageInvoiced"
}
},
"properties": {
"invoiced": {
"type": "Number"
},
"clientFk": {
"id": true
}
},
"relations": {
"client": {
"type": "belongsTo",
"model": "client",
"foreignKey": "clientFk"
}
}
}

View File

@ -0,0 +1,3 @@
module.exports = function(Self) {
require('../methods/expedition/filter.js')(Self);
};

View File

@ -0,0 +1,3 @@
module.exports = function(Self) {
require('../methods/sale/filter.js')(Self);
};

View File

@ -41,6 +41,11 @@
"foreignKey": "itemFk",
"required": true
},
"itemTag": {
"type": "hasMany",
"model": "ItemTag",
"foreignKey": "itemFk"
},
"ticket": {
"type": "belongsTo",
"model": "Ticket",

View File

@ -1,3 +1,3 @@
module.exports = function(Self) {
require('../methods/ticket/crudTicketObservations.js')(Self);
require('../methods/notes/crudTicketObservation.js')(Self);
};

View File

@ -0,0 +1,15 @@
module.exports = function(Self) {
require('../methods/packaging/crudTicketPackaging')(Self);
Self.validateBinded('quantity', validateQuantity, {
message: 'Quantity cannot be zero',
allowNull: false,
allowBlank: false
});
function validateQuantity(quantity) {
return !isNaN(quantity) && quantity != 0;
}
Self.validatesPresenceOf('packagingFk', {message: 'Package cannot be blank'});
};

View File

@ -0,0 +1,3 @@
module.exports = function(Self) {
require('../methods/ticketTracking/filter')(Self);
};

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