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

This commit is contained in:
Javi Gallego 2018-05-08 13:40:53 +02:00
commit d6be8f8f93
132 changed files with 1111 additions and 841 deletions

View File

@ -18,17 +18,19 @@
<vn-vertical vn-one pad-medium-h> <vn-vertical vn-one pad-medium-h>
<vn-horizontal ng-repeat="insurance in classification.creditInsurances track by insurance.id"> <vn-horizontal ng-repeat="insurance in classification.creditInsurances track by insurance.id">
<vn-one> <vn-one>
<vn-label translate>Credit</vn-label> <vn-label-value label="Credit"
<span>{{::insurance.credit}}</span> value="{{::insurance.credit}}">
</vn-label-value>
</vn-one> </vn-one>
<vn-one> <vn-one>
<vn-label translate>Grade</vn-label> <vn-label-value label="Grade"
<span ng-if="!insurance.grade">-</span> value="{{::insurance.grade}}">
<span ng-if="insurance.grade">{{::insurance.grade}}</span> </vn-label-value>
</vn-one> </vn-one>
<vn-one> <vn-one>
<vn-label translate>Date</vn-label> <vn-label-value label="Date"
<span>{{::insurance.created | date:'dd/MM/yyyy' }}</span> value="{{::insurance.created | date:'dd/MM/yyyy' }}">
</vn-label-value>
</vn-one> </vn-one>
</vn-horizontal> </vn-horizontal>
</vn-vertical> </vn-vertical>

View File

@ -1,27 +1,28 @@
<mg-ajax path="/client/api/CreditInsurances/filter" options="vnIndexNonAuto"></mg-ajax> <mg-ajax path="/client/api/CreditInsurances/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Requested credits</vn-title> <vn-title>Requested credits</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)"> <vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h field="credit" text="Credit"></vn-column-header> <vn-column-header vn-one pad-medium-h field="credit" text="Credit"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="grade" text="Grade"></vn-column-header> <vn-column-header vn-one pad-medium-h field="grade" text="Grade"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="created" text="Created" default-order="DESC"></vn-column-header> <vn-column-header vn-two pad-medium-h field="created" text="Created" default-order="DESC"></vn-column-header>
</vn-grid-header> </vn-grid-header>
<vn-one class="list list-content"> <vn-one class="list list-content">
<vn-horizontal <vn-horizontal
vn-one class="list list-element text-center" vn-one class="list list-element text-center"
pad-small-bottom pad-small-bottom
ng-repeat="insurance in index.model.instances track by insurance.id"> ng-repeat="insurance in $ctrl.instances track by insurance.id">
<vn-one pad-medium-h>{{::insurance.credit}}</vn-one> <vn-one pad-medium-h>{{::insurance.credit}}</vn-one>
<vn-one pad-medium-h>{{::insurance.grade}}</vn-one> <vn-one pad-medium-h>{{::insurance.grade}}</vn-one>
<vn-two pad-medium-h>{{::insurance.created | date: 'dd/MM/yyyy'}}</vn-two> <vn-two pad-medium-h>{{::insurance.created | date: 'dd/MM/yyyy'}}</vn-two>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-one>
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</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-horizontal vn-one class="list list-footer"></vn-horizontal>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>
<a ui-sref="clientCard.creditInsurance.create({classificationId: {{index.params.classificationId}}})" <a ui-sref="clientCard.creditInsurance.create({classificationId: {{index.params.classificationId}}})"
fixed-bottom-right vn-tooltip="New classification" vn-bind="+" tooltip-position="left" ng-if="!$ctrl.isClosed"> fixed-bottom-right vn-tooltip="New classification" vn-bind="+" tooltip-position="left" ng-if="!$ctrl.isClosed">

View File

@ -1,28 +1,28 @@
<mg-ajax path="/client/api/ClientCredits/filter" options="vnIndexNonAuto"></mg-ajax> <mg-ajax path="/client/api/ClientCredits/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Credit</vn-title> <vn-title>Credit</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)"> <vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h field="amount" text="Credit"></vn-column-header> <vn-column-header vn-one pad-medium-h field="amount" text="Credit"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="created" text="Since" default-order="ASC"></vn-column-header> <vn-column-header vn-two pad-medium-h field="created" text="Since" default-order="ASC"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="worker.firstName" text="Employee" order-locked></vn-column-header> <vn-column-header vn-two pad-medium-h field="worker.firstName" text="Employee" order-locked></vn-column-header>
</vn-grid-header> </vn-grid-header>
<vn-one class="list list-content"> <vn-one class="list list-content">
<vn-horizontal <vn-horizontal
vn-one class="list list-element text-center" vn-one class="list list-element text-center"
pad-small-bottom pad-small-bottom
ng-repeat="credit in index.model.instances track by credit.id"> ng-repeat="credit in $ctrl.instances track by credit.id">
<vn-one pad-medium-h>{{::credit.amount | number:2}} €</vn-one> <vn-one pad-medium-h>{{::credit.amount | number:2}} €</vn-one>
<vn-two pad-medium-h>{{::credit.created | date:'dd/MM/yyyy HH:mm'}}</vn-two> <vn-two pad-medium-h>{{::credit.created | date:'dd/MM/yyyy HH:mm'}}</vn-two>
<vn-two pad-medium-h>{{::credit.worker.firstName}} {{::credit.worker.name}}</vn-two> <vn-two pad-medium-h>{{::credit.worker.firstName}} {{::credit.worker.name}}</vn-two>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-one>
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</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-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-vertical>
</vn-card> </vn-card>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>
<a ui-sref="clientCard.credit.create" vn-bind="+" fixed-bottom-right> <a ui-sref="clientCard.credit.create" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button> <vn-float-button icon="add"></vn-float-button>

View File

@ -2,36 +2,35 @@
<mg-ajax path="/client/api/greuges/{{edit.params.id}}/sumAmount" options="mgEdit"></mg-ajax> <mg-ajax path="/client/api/greuges/{{edit.params.id}}/sumAmount" options="mgEdit"></mg-ajax>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Greuge</vn-title> <vn-title>Greuge</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)"> <vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h field="shipped" text="Date" default-order="ASC"></vn-column-header> <vn-column-header vn-one pad-medium-h field="shipped" text="Date" default-order="ASC"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="description" text="Comment"></vn-column-header> <vn-column-header vn-two pad-medium-h field="description" text="Comment"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="amount" text="Amount"></vn-column-header> <vn-column-header vn-one pad-medium-h field="amount" text="Amount"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="greugeTypeFk" text="Type"></vn-column-header> <vn-column-header vn-one pad-medium-h field="greugeTypeFk" text="Type"></vn-column-header>
</vn-grid-header> </vn-grid-header>
<vn-one class="list list-content"> <vn-one class="list list-content">
<vn-horizontal <vn-horizontal
class="list list-element text-center" class="list list-element text-center"
pad-small-bottom pad-small-bottom
ng-repeat="greuge in $ctrl.instances track by $index"> ng-repeat="greuge in $ctrl.instances track by $index">
<vn-one pad-medium-h>{{greuge.shipped | date:'dd/MM/yyyy HH:mm' }}</vn-one> <vn-one pad-medium-h>{{::greuge.shipped | date:'dd/MM/yyyy HH:mm' }}</vn-one>
<vn-two pad-medium-h>{{greuge.description}}</vn-two> <vn-two pad-medium-h>{{::greuge.description}}</vn-two>
<vn-one pad-medium-h>{{greuge.amount | number:2}} €</vn-one> <vn-one pad-medium-h>{{::greuge.amount | number:2}} €</vn-one>
<vn-one pad-medium-h>{{greuge.greugeType.name}}</vn-one> <vn-one pad-medium-h>{{::greuge.greugeType.name}}</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 text-center">
<vn-one pad-medium-h></vn-one>
<vn-two pad-medium-h></vn-two>
<vn-one pad-medium-h ng-if="index.model.count > 0">{{edit.model.sumAmount | number:2}} €</vn-one>
<vn-one pad-medium-h></vn-one>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-vertical>
<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 text-center">
<vn-one pad-medium-h></vn-one>
<vn-two pad-medium-h></vn-two>
<vn-one pad-medium-h ng-if="index.model.count > 0">{{edit.model.sumAmount | number:2}} €</vn-one>
<vn-one pad-medium-h></vn-one>
</vn-horizontal>
<!--<vn-paging margin-large-top vn-one index="index" total="index.model.count"></vn-paging>-->
<vn-auto-paging margin-large-top vn-one index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical>
</vn-card> </vn-card>
<vn-auto-paging margin-large-top vn-one index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>
<a ui-sref="clientCard.greuge.create" vn-bind="+" fixed-bottom-right> <a ui-sref="clientCard.greuge.create" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button> <vn-float-button icon="add"></vn-float-button>

View File

@ -14,11 +14,11 @@
</vn-card> </vn-card>
<vn-card margin-medium-top> <vn-card margin-medium-top>
<vn-item-client <vn-item-client
ng-repeat="client in index.model.instances" ng-repeat="client in $ctrl.clients"
client="client"> client="client">
</vn-item-client> </vn-item-client>
</vn-card> </vn-card>
<vn-paging index="index" total="index.model.count"></vn-paging> <vn-auto-paging index="index" total="index.model.count" items="$ctrl.clients"></vn-auto-paging>
</div> </div>
</div> </div>
<a ui-sref="create" vn-bind="+" fixed-bottom-right> <a ui-sref="create" vn-bind="+" fixed-bottom-right>

View File

@ -2,13 +2,19 @@ import ngModule from '../module';
import './item-client'; import './item-client';
export default class Controller { export default class Controller {
constructor($scope) { constructor($scope) {
this.$scope = $scope; this.$scope = $scope;
this.clientSelected = null; this.clientSelected = null;
} }
search(index) { search(index) {
index.accept(); this.clients = [];
index.accept().then(res => {
this.clients = res.instances;
});
} }
openSummary(client) { openSummary(client) {
this.clientSelected = client; this.clientSelected = client;
this.$scope.dialogSummaryClient.show(); this.$scope.dialogSummaryClient.show();

View File

@ -1,38 +1,34 @@
<mg-ajax path="/client/api/InvoiceOuts/filter" options="vnIndexNonAuto"></mg-ajax> <mg-ajax path="/client/api/InvoiceOuts/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Invoices</vn-title> <vn-title>Invoices</vn-title>
<vn-vertical style="text-align: center;"> <vn-vertical style="text-align: center;">
<vn-grid-header on-order="$ctrl.onOrder(field, order)"> <vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one field="ref" text="Reference" default-order="ASC"></vn-column-header> <vn-column-header vn-one field="ref" text="Reference" default-order="ASC"></vn-column-header>
<vn-column-header vn-one field="issued" text="Issue date"></vn-column-header> <vn-column-header vn-one field="issued" text="Issue date"></vn-column-header>
<vn-column-header vn-one field="dued" text="Due date"></vn-column-header> <vn-column-header vn-one field="dued" text="Due date"></vn-column-header>
<vn-column-header vn-one field="amount" text="Amount"></vn-column-header> <vn-column-header vn-one field="amount" text="Amount"></vn-column-header>
</vn-grid-header> </vn-grid-header>
<vn-vertical> <vn-vertical>
<vn-one <vn-one
ng-if="index.model.count > 0" ng-if="index.model.count > 0"
class="list list-content"> class="list list-content">
<vn-horizontal <vn-horizontal
class="list list-element" class="list list-element"
pad-small-bottom pad-small-bottom
ng-repeat="invoice in index.model.instances track by greuge.id"> ng-repeat="invoice in $ctrl.instances track by greuge.id">
<vn-one>{{::invoice.ref}}</vn-one> <vn-one>{{::invoice.ref}}</vn-one>
<vn-one>{{::invoice.issued | date:'dd/MM/yyyy' }}</vn-one> <vn-one>{{::invoice.issued | date:'dd/MM/yyyy' }}</vn-one>
<vn-one>{{::invoice.dued | date:'dd/MM/yyyy' }}</vn-one> <vn-one>{{::invoice.dued | date:'dd/MM/yyyy' }}</vn-one>
<vn-one>{{::invoice.amount | currency:'€':2}}</vn-one> <vn-one>{{::invoice.amount | currency:'€':2}}</vn-one>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-one>
<vn-one <vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
ng-if="index.model.count === 0" </vn-vertical>
pad-small-v translate> <vn-horizontal vn-one class="list list-footer"></vn-horizontal>
No results
</vn-one>
</vn-vertical> </vn-vertical>
<vn-horizontal vn-one class="list list-footer"></vn-horizontal>
</vn-vertical> </vn-vertical>
<vn-paging margin-large-top vn-one index="index" total="index.model.count"></vn-paging>
</vn-vertical>
</vn-card> </vn-card>
<vn-auto-paging margin-large-top vn-one index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>

View File

@ -1,30 +1,30 @@
<mg-ajax path="/client/api/Mandates/filter" options="vnIndexNonAuto"></mg-ajax> <mg-ajax path="/client/api/Mandates/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Mandate</vn-title> <vn-title>Mandate</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)"> <vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h field="id" text="Id"></vn-column-header> <vn-column-header vn-one pad-medium-h field="id" text="Id"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="companyFk" text="Company"></vn-column-header> <vn-column-header vn-one pad-medium-h field="companyFk" text="Company"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="mandateTypeFk" text="Type"></vn-column-header> <vn-column-header vn-one pad-medium-h field="mandateTypeFk" text="Type"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="created" text="Register date" default-order="ASC"></vn-column-header> <vn-column-header vn-one pad-medium-h field="created" text="Register date" default-order="ASC"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="finished" text="End date"></vn-column-header> <vn-column-header vn-one pad-medium-h field="finished" text="End date"></vn-column-header>
</vn-grid-header> </vn-grid-header>
<vn-one class="list list-content"> <vn-one class="list list-content">
<vn-horizontal <vn-horizontal
vn-one class="list list-element text-center" vn-one class="list list-element text-center"
pad-small-bottom pad-small-bottom
ng-repeat="mandate in index.model.instances track by mandate.id"> ng-repeat="mandate in $ctrl.instances track by mandate.id">
<vn-one pad-medium-h>{{::mandate.id}}</vn-one> <vn-one pad-medium-h>{{::mandate.id}}</vn-one>
<vn-one pad-medium-h>{{::mandate.company.code}}</vn-one> <vn-one pad-medium-h>{{::mandate.company.code}}</vn-one>
<vn-one pad-medium-h>{{::mandate.mandateType.name}}</vn-one> <vn-one pad-medium-h>{{::mandate.mandateType.name}}</vn-one>
<vn-one pad-medium-h>{{::mandate.created | date:'dd/MM/yyyy HH:mm' }}</vn-one> <vn-one pad-medium-h>{{::mandate.created | date:'dd/MM/yyyy HH:mm' }}</vn-one>
<vn-one pad-medium-h>{{::mandate.finished | date:'dd/MM/yyyy HH:mm' || '-'}}</vn-one> <vn-one pad-medium-h>{{::mandate.finished | date:'dd/MM/yyyy HH:mm' || '-'}}</vn-one>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-one>
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</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-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-vertical>
</vn-card> </vn-card>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>

View File

@ -1,36 +1,36 @@
<mg-ajax path="/client/api/Recoveries/filter" options="vnIndexNonAuto"></mg-ajax> <mg-ajax path="/client/api/Recoveries/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Recovery</vn-title> <vn-title>Recovery</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)"> <vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h field="started" text="Since" default-order="ASC"></vn-column-header> <vn-column-header vn-one pad-medium-h field="started" text="Since" default-order="ASC"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="finished" text="To"></vn-column-header> <vn-column-header vn-one pad-medium-h field="finished" text="To"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="amount" text="Amount"></vn-column-header> <vn-column-header vn-one pad-medium-h field="amount" text="Amount"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="period" text="Period"></vn-column-header> <vn-column-header vn-one pad-medium-h field="period" text="Period"></vn-column-header>
</vn-grid-header> </vn-grid-header>
<vn-one class="list list-content"> <vn-one class="list list-content">
<vn-horizontal <vn-horizontal
vn-one class="list list-element text-center" vn-one class="list list-element text-center"
pad-small-bottom pad-small-bottom
ng-repeat="recovery in $ctrl.instances track by $index"> ng-repeat="recovery in $ctrl.instances track by $index">
<vn-none pad-medium-h style="color:#FFA410;"> <vn-none pad-medium-h style="color:#FFA410;">
<i class="material-icons pointer" <i class="material-icons pointer"
vn-tooltip="Finish that recovery period" vn-tooltip="Finish that recovery period"
ng-if="!recovery.finished" ng-if="!recovery.finished"
ng-click="$ctrl.setFinished(recovery)">lock</i> ng-click="$ctrl.setFinished(recovery)">lock</i>
</vn-none> </vn-none>
<vn-one pad-medium-h>{{::recovery.started | date:'dd/MM/yyyy' }}</vn-one> <vn-one pad-medium-h>{{::recovery.started | date:'dd/MM/yyyy' }}</vn-one>
<vn-one pad-medium-h>{{recovery.finished | date:'dd/MM/yyyy' }}</vn-one> <vn-one pad-medium-h>{{recovery.finished | date:'dd/MM/yyyy' }}</vn-one>
<vn-one pad-medium-h>{{::recovery.amount | currency:'€':0}}</vn-one> <vn-one pad-medium-h>{{::recovery.amount | currency:'€':0}}</vn-one>
<vn-one pad-medium-h>{{::recovery.period}}</vn-one> <vn-one pad-medium-h>{{::recovery.period}}</vn-one>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-one>
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</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-horizontal vn-one class="list list-footer"></vn-horizontal>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging> </vn-vertical>
</vn-vertical>
</vn-card> </vn-card>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>
<a ui-sref="clientCard.recovery.create" vn-bind="+" fixed-bottom-right> <a ui-sref="clientCard.recovery.create" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button> <vn-float-button icon="add"></vn-float-button>

View File

@ -56,12 +56,14 @@ class AutoPaging {
startScroll() { startScroll() {
this.watchScroll = true; this.watchScroll = true;
this.checkPosition(); this.checkPosition();
angular.element(this.$window).bind("wheel", this.handlerScroll); let mainView = this.$window.document.querySelector('.main-view > ui-view.ng-scope');
angular.element(mainView).bind("scroll", this.handlerScroll);
} }
cancelScroll() { cancelScroll() {
this.watchScroll = false; this.watchScroll = false;
angular.element(this.$window).unbind("wheel", this.handlerScroll); let mainView = this.$window.document.querySelector('.main-view > ui-view.ng-scope');
angular.element(mainView).unbind("scroll", this.handlerScroll);
} }
checkScroll() { checkScroll() {

View File

@ -1,5 +1,6 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Input from '../../lib/input'; import Input from '../../lib/input';
import asignProps from '../../lib/asign-props';
import './style.scss'; import './style.scss';
/** /**
@ -214,17 +215,19 @@ export default class Autocomplete extends Input {
staticData: this.data staticData: this.data
}); });
Object.assign(this.$.dropDown, { asignProps(this, this.$.dropDown, [
valueField: this.valueField, 'valueField',
showField: this.showField, 'showField',
selectFields: this.getFields(), 'where',
where: this.where, 'order',
order: this.order, 'showFilter',
parent: this.input, 'multiple',
multiple: this.multiple, 'limit',
limit: this.limit, '$transclude'
$transclude: this.$transclude ]);
});
this.$.dropDown.selectFields = this.getFields();
this.$.dropDown.parent = this.input;
this.$.dropDown.show(search); this.$.dropDown.show(search);
} }
} }

View File

@ -1,3 +1,7 @@
<button type = "*[typeName]*" class="*[className]*" *[enabled]* translate> <button type="{{::$ctrl.type}}" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored hfj">
*[label]* <span translate>{{$ctrl.label}}</span>
<vn-icon
icon="{{::$ctrl.icon}}"
class="{{::$ctrl.icon}}">
</vn-icon>
</button> </button>

View File

@ -1,17 +1,22 @@
import ngModule from '../../module'; import ngModule from '../../module';
import template from './button.html'; import Input from '../../lib/input';
import './style.scss';
directive.$inject = ['vnTemplate']; export default class Button extends Input {
export default function directive(vnTemplate) { constructor($element) {
return { super($element);
restrict: 'E', this.input = this.element.querySelector('.mdl-button');
template: (_, $attrs) => }
vnTemplate.get(template, $attrs, {
label: 'Submit',
className: 'mdl-button mdl-js-button mdl-button--raised mdl-button--colored',
enabled: 'true',
typeName: 'button'
})
};
} }
ngModule.directive('vnButton', directive); Button.$inject = ['$element'];
ngModule.component('vnButton', {
controller: Button,
template: require('./button.html'),
bindings: {
label: '@?',
disabled: '<?',
icon: '@?'
}
});

View File

@ -0,0 +1,5 @@
vn-button {
& i {
margin-top: 6px;
}
}

View File

@ -22,9 +22,7 @@ ngModule.component('vnIconButton', {
template: require('./icon-button.html'), template: require('./icon-button.html'),
bindings: { bindings: {
icon: '@', icon: '@',
className: '@?', enabled: '<?'
enabled: '<?',
label: '@?'
} }
}); });

View File

@ -1,27 +1,11 @@
<div class="icon-menu" ng-click="$ctrl.showDropDown = true"> <div class="icon-menu">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored icon-square icon-menu__button"> <button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored icon-menu__button" ng-click="$ctrl.onClick($event)">
<vn-label vn-none translate>{{::$ctrl.label}}</vn-label>
<vn-icon vn-none icon="{{::$ctrl.icon}}"></vn-icon> <vn-icon vn-none icon="{{::$ctrl.icon}}"></vn-icon>
<vn-icon vn-none class="icon-menu__arrow_down" icon="keyboard_arrow_down"></vn-icon> <vn-icon vn-none class="icon-menu__arrow_down" icon="keyboard_arrow_down"></vn-icon>
</button> </button>
<div ng-if="!$ctrl.findMore"> <vn-drop-down
<vn-drop-down vn-id="drop-down"
items="$ctrl.items" on-select="$ctrl.onDropDownSelect(value)">
show="$ctrl.showDropDown" </vn-drop-down>
selected="$ctrl.selected"
filter="true"
parent="$ctrl.element">
</vn-drop-down>
</div>
<div ng-if="$ctrl.findMore">
<vn-drop-down
items="$ctrl.items"
show="$ctrl.showDropDown"
selected="$ctrl.selected"
filter="true"
load-more="$ctrl.getItems()"
show-load-more="$ctrl.maxRow"
filter-action="$ctrl.findItems(search)"
parent="$ctrl.element">
</vn-drop-down>
</div>
</div> </div>

View File

@ -1,131 +1,88 @@
import ngModule from '../../module'; import ngModule from '../../module';
import Input from '../../lib/input';
import asignProps from '../../lib/asign-props';
import './style.scss'; import './style.scss';
export default class IconMenu { export default class IconMenu extends Input {
constructor($element, $http, $timeout) { constructor($element, $scope, $transclude) {
this.$element = $element; super($element, $scope);
this.$http = $http; this.$transclude = $transclude;
this.$timeout = $timeout; this.input = this.element.querySelector('.mdl-button');
this._showDropDown = false; this.valueField = 'id';
this.finding = false; this.showField = 'name';
this.findMore = false;
this.element = $element[0];
} }
get showDropDown() { getFields() {
return this._showDropDown; let fields = [];
fields.push(this.valueField);
fields.push(this.showField);
if (this.selectFields)
for (let field of this.selectFields)
fields.push(field);
return fields;
} }
set showDropDown(value) { onClick(event) {
this._showDropDown = value; event.preventDefault();
this.showDropDown();
} }
findItems(search) { onDropDownSelect(value) {
if (!this.url) this.field = value;
return this.items ? this.items : [];
if (search && !this.finding) { if (this.onChange)
let filter = {where: {name: {regexp: search}}}; this.onChange({value});
let json = JSON.stringify(filter);
this.finding = true;
this.$http.get(`${this.url}?filter=${json}`).then(
json => {
this.items = json.data;
this.finding = false;
},
() => {
this.finding = false;
}
);
} else if (!search && !this.finding) {
this.maxRow = 10;
this.items = [];
this.getItems();
}
} }
getItems() { showDropDown() {
let filter = {}; Object.assign(this.$.dropDown.$.model, {
url: this.url,
if (this.maxRow) { staticData: this.data
if (this.items) {
filter.skip = this.items.length;
}
filter.limit = this.maxRow;
filter.order = 'name ASC';
}
let json = JSON.stringify(filter);
this.$http.get(`${this.url}?filter=${json}`).then(
json => {
if (json.data.length)
json.data.forEach(
el => {
this.items.push(el);
}
);
else
this.maxRow = false;
}
);
}
$onInit() {
if (!this.items && this.url) {
this.items = [];
this.getItems();
}
this.findMore = this.url && this.maxRow;
this.mouseFocus = false;
this.focused = false;
this.$element.bind('mouseover', e => {
this.$timeout(() => {
this.mouseFocus = true;
this.showDropDown = this.focused;
});
}); });
this.$element.bind('mouseout', () => { asignProps(this, this.$.dropDown, [
this.$timeout(() => { 'valueField',
this.mouseFocus = false; 'showField',
this.showDropDown = this.focused; 'where',
}); 'order',
}); 'showFilter',
this.$element.bind('focusin', e => { 'multiple',
this.$timeout(() => { 'limit',
this.focused = true; '$transclude'
this.showDropDown = true; ]);
});
});
this.$element.bind('focusout', e => {
this.$timeout(() => {
this.focused = false;
this.showDropDown = this.mouseFocus;
});
});
}
$onDestroy() { this.$.dropDown.selectFields = this.getFields();
this.$element.unbind('mouseover'); this.$.dropDown.parent = this.input;
this.$element.unbind('mouseout'); this.$.dropDown.show();
this.$element.unbind('focusin');
this.$element.unbind('focusout');
} }
} }
IconMenu.$inject = ['$element', '$http', '$timeout']; IconMenu.$inject = ['$element', '$scope', '$transclude'];
ngModule.component('vnIconMenu', { ngModule.component('vnIconMenu', {
template: require('./icon-menu.html'), template: require('./icon-menu.html'),
bindings: { bindings: {
url: '@?', url: '@?',
items: '<?', data: '<?',
icon: '@', showField: '@?',
maxRow: '@?', valueField: '@?',
selected: '=' selectFields: '<?',
disabled: '<?',
where: '@?',
order: '@?',
label: '@',
initialData: '<?',
field: '=?',
limit: '<?',
showFilter: '<?',
selection: '<?',
multiple: '<?',
onChange: '&?',
icon: '@?'
},
transclude: {
tplItem: '?tplItem'
}, },
controller: IconMenu controller: IconMenu
}); });

View File

@ -3,10 +3,15 @@ vn-icon-menu{
.icon-menu__button { .icon-menu__button {
padding: 0 10px; padding: 0 10px;
} }
vn-label{
float: left;
margin-top: 1px;
}
vn-icon{ vn-icon{
float: left; float: left;
margin-top: 3px;
} }
vn-icon.icon-menu__arrow_down{ vn-icon.icon-menu__arrow_down{
margin:2px 0 0 5px; margin: 6px 0 0 5px;
} }
} }

View File

@ -1,19 +1 @@
<vn-vertical class="multi-check" vn-none class="multi-check {{$ctrl.className}}" tabindex="1" ng-blur="$ctrl.onBlur()"> <vn-check field="$ctrl.checkAll"></vn-check>
<vn-one>
<vn-horizontal>
<vn-none class="primaryCheckbox" ng-if="$ctrl.checkAll===0">
<vn-icon vn-none icon="check_box_outline_blank" ng-click="$ctrl.checkAll = 1"></vn-icon>
</vn-none>
<vn-none class="primaryCheckbox color" ng-if="$ctrl.checkAll===1">
<vn-icon vn-none icon="check_box" ng-click="$ctrl.checkAll = 0"></vn-icon>
</vn-none>
<vn-none class="primaryCheckbox color" ng-if="$ctrl.checkAll===2">
<vn-icon vn-none icon="indeterminate_check_box" ng-click="$ctrl.checkAll = 0"></vn-icon>
</vn-none>
<vn-icon vn-none class="arrow_down" icon="keyboard_arrow_down" ng-click="$ctrl.showDropDown = true"></vn-icon>
</vn-horizontal>
</vn-one>
<vn-one>
<vn-drop-down vn-none items="$ctrl.options" show="$ctrl.showDropDown" selected="$ctrl.type"></vn-drop-down>
</vn-one>
</vn-vertical>

View File

@ -3,49 +3,14 @@ import './multi-check.scss';
/** /**
* Draw checkbox with a drop-down and multi options * Draw checkbox with a drop-down and multi options
* @param {SmallInt} checkAll Primary input-check state: 0 -> uncheck, 1 -> checked, 2 -> indeterminate checked * @param {SmallInt} checkAll Primary input-check state: 0 -> uncheck, 1 -> checked
* @param {Array} options List of options shown in drop-down * @param {Array} data List of options shown in drop-down
* @param {Array} models Elements to check / unCheck * @param {Array} models Elements to check / unCheck
* @param {String} className Optional css class name
*/ */
export default class MultiCheck { export default class MultiCheck {
constructor($timeout) { constructor() {
this.$timeout = $timeout; this._checkAll = false;
this._checkAll = 0; this.checkField = 'checked';
this._models = [];
this._type = {};
this.showDropDown = false;
}
get type() {
return this._type;
}
set type(value) {
if (value && value.id) {
this._type = value;
switch (value.id) {
case 'all':
this.checkAll = 1;
break;
case 'any':
this.checkAll = 0;
break;
default:
this.checkAll = 2;
break;
}
}
this._type = {};
this.showDropDown = false;
}
get models() {
return this._models;
}
set models(value) {
this._models = value;
} }
get checkAll() { get checkAll() {
@ -58,49 +23,20 @@ export default class MultiCheck {
} }
switchChecks() { switchChecks() {
if (this.models) if (!this.data) return;
this.models.forEach( this.data.forEach(el => {
el => { el[this.checkField] = this._checkAll;
let checked; });
if (this.type.id && this.type.id !== 'all' && this.type.id !== 'any') {
if (this.type.id.length > 3 && this.type.id.substr(0, 3) === 'no-') {
let label = this.type.id.replace('no-', '');
checked = Boolean(el[label]) === false;
} else if (this.type.id.length > 6 && this.type.id.substr(0, 6) === 'equal-') {
let label = this.type.id.replace('equal-', '');
checked = (el[label] && el[label] === this.type.name);
} else {
checked = Boolean(el[this.type.id]) === true;
}
} else {
checked = this.checkAll === 1;
}
el.checked = checked;
}
);
}
$onChanges() {
this.type = {};
this.checkAll = 0;
}
onBlur() {
this.$timeout(() => {
this.showDropDown = false;
}, 200);
} }
} }
MultiCheck.$inject = ['$timeout'];
ngModule.component('vnMultiCheck', { ngModule.component('vnMultiCheck', {
template: require('./multi-check.html'), template: require('./multi-check.html'),
controller: MultiCheck, controller: MultiCheck,
bindings: { bindings: {
checkAll: '=', data: '=',
options: '<', checkField: '<?',
models: '<', checkAll: '=?'
className: '@?'
} }
}); });

View File

@ -13,16 +13,7 @@ describe('Component vnMultiCheck', () => {
controller = $componentController('vnMultiCheck', {}); controller = $componentController('vnMultiCheck', {});
})); }));
describe('models()', () => { describe('checkAll() setter', () => {
it(`should set controller _models property with the argument received`, () => {
let argument = 'I am the model';
controller.models = argument;
expect(controller._models).toEqual(argument);
});
});
describe('checkAll()', () => {
it(`should set controller _checkAll property with the argument received then call switchChecks()`, () => { it(`should set controller _checkAll property with the argument received then call switchChecks()`, () => {
let argument = 'I am the model'; let argument = 'I am the model';
spyOn(controller, 'switchChecks'); spyOn(controller, 'switchChecks');
@ -35,129 +26,18 @@ describe('Component vnMultiCheck', () => {
describe('switchChecks()', () => { describe('switchChecks()', () => {
it(`should set checked property inside each existing elemenet when id begings with no-`, () => { it(`should set checked property inside each existing elemenet when id begings with no-`, () => {
controller.type = {id: 'no-name'}; controller.data = [
controller.models = [
{name: 'name'}, {name: 'name'},
{name: null} {name: null}
]; ];
expect(controller._models[0].checked).not.toBeDefined(); expect(controller.data[0].checked).not.toBeDefined();
expect(controller._models[1].checked).not.toBeDefined(); expect(controller.data[1].checked).not.toBeDefined();
controller._checkAll = 1; controller._checkAll = 1;
controller.switchChecks(); controller.switchChecks();
expect(controller._models[0].checked).toBeTruthy(); expect(controller.data[0].checked).toBeTruthy();
expect(controller._models[1].checked).toBeTruthy(); expect(controller.data[1].checked).toBeTruthy();
});
it(`should set checked property inside each existing elemenet when id begings with equal-`, () => {
controller.type = {id: 'equal-name', name: 'name'};
controller.models = [
{name: null},
{name: 'name'}
];
expect(controller._models[0].checked).not.toBeDefined();
expect(controller._models[1].checked).not.toBeDefined();
controller._checkAll = 1;
controller.switchChecks();
expect(controller._models[0].checked).toBeTruthy();
expect(controller._models[1].checked).toBeTruthy();
});
it(`should set checked property inside each existing elemenet when begings with anything but any, all, no- or equal-`, () => {
controller.type = {id: 'name'};
controller.models = [
{name: null},
{name: 'name'}
];
expect(controller._models[0].checked).not.toBeDefined();
expect(controller._models[1].checked).not.toBeDefined();
controller._checkAll = 1;
controller.switchChecks();
expect(controller._models[0].checked).toBeTruthy();
expect(controller._models[1].checked).toBeTruthy();
});
describe('when id is any', () => {
it('should set element checked property based on controller._checkAll', () => {
controller.type = {id: 'any'};
controller.models = [
{name: 'name'}
];
expect(controller._models[0].checked).not.toBeDefined();
controller._checkAll = 1;
controller.switchChecks();
expect(controller._models[0].checked).toBeTruthy();
controller._checkAll = 0;
controller.switchChecks();
expect(controller._models[0].checked).toBeFalsy();
controller._checkAll = 2;
controller.switchChecks();
expect(controller._models[0].checked).toBeFalsy();
});
});
describe('when id is all', () => {
it('should set element checked property based on controller._checkAll property', () => {
controller.type = {id: 'all'};
controller.models = [
{name: 'name'}
];
expect(controller._models[0].checked).not.toBeDefined();
controller._checkAll = 1;
controller.switchChecks();
expect(controller._models[0].checked).toBeTruthy();
controller._checkAll = 0;
controller.switchChecks();
expect(controller._models[0].checked).toBeFalsy();
controller._checkAll = 2;
controller.switchChecks();
expect(controller._models[0].checked).toBeFalsy();
});
});
});
describe('$onChanges()', () => {
it('should set controller.type to empty object and checkAll to zero', () => {
controller.type = {id: 'all'};
controller._checkAll = 1;
controller.$onChanges();
expect(controller.type).toEqual({});
expect(controller._checkAll).toEqual(0);
});
});
describe('type setter', () => {
it('should set controller.type to empty object and checkAll based on controller.type.id', () => {
let value = {id: 'all'};
controller._checkAll = 0;
controller.type = value;
expect(controller.type).toEqual({});
expect(controller._checkAll).toEqual(1);
value = {id: 'any'};
controller.type = value;
expect(controller.type).toEqual({});
expect(controller._checkAll).toEqual(0);
value = {id: 'any other id name'};
controller.type = value;
expect(controller.type).toEqual({});
expect(controller._checkAll).toEqual(2);
}); });
}); });
}); });

View File

@ -1,6 +1,6 @@
<section class="step-control"> <section class="step-control">
<section class="steps"> <section class="steps">
<section class="step" ng-repeat="step in $ctrl.steps track by $index"> <section class="step" ng-repeat="step in $ctrl._steps track by $index">
<section class="circle" <section class="circle"
vn-tooltip="{{::step.name}}" vn-tooltip="{{::step.name}}"
tooltip-position="down" tooltip-position="down"

View File

@ -6,6 +6,15 @@ export default class StepControl {
this.$state = $state; this.$state = $state;
} }
set steps(steps) {
if (!steps) return;
this._steps = steps;
if (this.currentStepIndex > 0)
this.$state.go(this._steps[0].state);
}
set currentState(state) { set currentState(state) {
let isAllowed = true; let isAllowed = true;
@ -17,7 +26,7 @@ export default class StepControl {
} }
get totalSteps() { get totalSteps() {
return this.steps.length; return this._steps.length;
} }
get currentState() { get currentState() {
@ -25,36 +34,34 @@ export default class StepControl {
} }
get currentStepIndex() { get currentStepIndex() {
for (let i = 0; i < this.steps.length; i++) { for (let i = 0; i < this._steps.length; i++) {
if (this.steps[i].state == this.$state.current.name) if (this._steps[i].state == this.$state.current.name)
return i; return i;
} }
} }
onPreviousClick() { onPreviousClick() {
let state = this.steps[this.currentStepIndex - 1].state; let state = this._steps[this.currentStepIndex - 1].state;
this.currentState = state; this.currentState = state;
} }
onNextClick() { onNextClick() {
let state = this.steps[this.currentStepIndex + 1].state; let state = this._steps[this.currentStepIndex + 1].state;
this.currentState = state; this.currentState = state;
} }
canMovePrevious() { canMovePrevious() {
return this.steps[0].state != this.currentState; return this.currentStepIndex > 0;
} }
canFinalize() { canFinalize() {
let lastStep = this.steps[this.totalSteps - 1]; return this.currentStepIndex === this.totalSteps - 1;
return lastStep.state == this.currentState;
} }
canMoveNext() { canMoveNext() {
let lastStep = this.steps[this.totalSteps - 1]; return this.currentStepIndex < this.totalSteps - 1;
return lastStep.state != this.currentState;
} }
} }

View File

@ -0,0 +1,6 @@
export default function(srcObject, dstObject, props) {
for (let prop of props)
if (srcObject[prop] !== undefined)
dstObject[prop] = srcObject[prop];
}

View File

@ -1,31 +1,28 @@
<mg-ajax path="/item/api/ItemLogs/getLog" options="vnIndexNonAuto"></mg-ajax> <mg-ajax path="/item/api/ItemLogs/getLog" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Item history</vn-title> <vn-title>Item history</vn-title>
<vn-grid-header on-order="$ctrl.onOrder(field, order)"> <vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-two pad-medium-h field="description" text="Description"></vn-column-header> <vn-column-header vn-two pad-medium-h field="description" text="Description"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="action" text="Action"></vn-column-header> <vn-column-header vn-one pad-medium-h field="action" text="Action"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="userFk" text="Changed by"></vn-column-header> <vn-column-header vn-one pad-medium-h field="userFk" text="Changed by"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="creationDate" text="Date" default-order="ASC"></vn-column-header> <vn-column-header vn-one pad-medium-h field="creationDate" text="Date" default-order="ASC"></vn-column-header>
</vn-grid-header> </vn-grid-header>
<vn-one class="list list-content"> <vn-one class="list list-content">
<vn-horizontal <vn-horizontal
class="list list-element text-center" class="list list-element text-center"
pad-small-bottom pad-small-bottom
ng-repeat="itemLog in index.model.instances track by itemLog.id"> ng-repeat="itemLog in index.model.instances track by itemLog.id">
<vn-two pad-medium-h>{{::itemLog.description}}</vn-two> <vn-two pad-medium-h>{{::itemLog.description}}</vn-two>
<vn-one pad-medium-h>{{::itemLog.action}}</vn-one> <vn-one pad-medium-h>{{::itemLog.action}}</vn-one>
<vn-one pad-medium-h>{{::itemLog.user.name}}</vn-one> <vn-one pad-medium-h>{{::itemLog.user.name}}</vn-one>
<vn-one pad-medium-h>{{::itemLog.creationDate | date:'dd/MM/yyyy HH:mm'}}</vn-one> <vn-one pad-medium-h>{{::itemLog.creationDate | date:'dd/MM/yyyy HH:mm'}}</vn-one>
</vn-horizontal> </vn-horizontal>
</vn-one> </vn-one>
<vn-horizontal vn-one class="list list-footer text-center"> <vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
<vn-one pad-medium-h></vn-one> <vn-horizontal vn-one class="list list-footer text-center"></vn-horizontal>
<vn-two pad-medium-h></vn-two> </vn-vertical>
<vn-one pad-medium-h></vn-one>
</vn-horizontal>
<vn-paging margin-large-top vn-one index="index" total="index.model.count"></vn-paging>
</vn-vertical>
</vn-card> </vn-card>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>

View File

@ -19,7 +19,6 @@
item="item"> item="item">
</vn-item-product> </vn-item-product>
</vn-card> </vn-card>
<!-- <vn-paging index="index" total="index.model.count"></vn-paging> -->
<vn-auto-paging index="index" total="index.model.count" items="$ctrl.items"></vn-auto-paging> <vn-auto-paging index="index" total="index.model.count" items="$ctrl.items"></vn-auto-paging>
</div> </div>
</div> </div>

View File

@ -3,6 +3,7 @@ import './product';
import './style.scss'; import './style.scss';
class ItemList { class ItemList {
constructor($http, $state, $scope) { constructor($http, $state, $scope) {
this.$http = $http; this.$http = $http;
this.$state = $state; this.$state = $state;
@ -11,15 +12,19 @@ class ItemList {
this.itemSelected = null; this.itemSelected = null;
this.items = []; this.items = [];
} }
search(index) { search(index) {
this.items = [];
index.accept().then(res => { index.accept().then(res => {
this.items = res.instances; this.items = res.instances;
}); });
} }
cloneItem(item) { cloneItem(item) {
this.itemSelected = item; this.itemSelected = item;
this.$scope.clone.show(); this.$scope.clone.show();
} }
onCloneAccept(response) { onCloneAccept(response) {
if (response == 'ACCEPT' && this.itemSelected) { if (response == 'ACCEPT' && this.itemSelected) {
this.$http.post(`/item/api/Items/${this.itemSelected.id}/clone`).then(res => { this.$http.post(`/item/api/Items/${this.itemSelected.id}/clone`).then(res => {
@ -30,6 +35,7 @@ class ItemList {
} }
this.itemSelected = null; this.itemSelected = null;
} }
showItemPreview(item) { showItemPreview(item) {
this.itemSelected = item; this.itemSelected = item;
this.$scope.preview.show(); this.$scope.preview.show();

View File

@ -42,3 +42,4 @@ Remove niche: Quitar nicho
Add barcode: Añadir código de barras Add barcode: Añadir código de barras
Remove barcode: Quitar código de barras Remove barcode: Quitar código de barras
Buyer: Comprador Buyer: Comprador
No results: Sin resultados

View File

@ -7,3 +7,4 @@ production: []
salix: [] salix: []
route: [] route: []
ticket: [item] ticket: [item]
order: []

1
client/order/index.js Normal file
View File

@ -0,0 +1 @@
export * from './src';

24
client/order/routes.json Normal file
View File

@ -0,0 +1,24 @@
{
"module": "order",
"name": "Orders",
"icon": "shopping_basket",
"validations": true,
"routes": [
{
"url": "/order",
"state": "order",
"abstract": true,
"component": "ui-view"
},
{
"url": "/list?q",
"state": "order.list",
"component": "vn-order-list"
},
{
"url": "/create",
"state": "order.create",
"component": "vn-order-create"
}
]
}

View File

@ -0,0 +1 @@
export * from './module';

View File

@ -0,0 +1 @@
Orders: Orders

View File

@ -0,0 +1 @@
Orders: Catálogo

View File

@ -0,0 +1,5 @@
import {ng} from 'vendor';
import 'core';
const ngModule = ng.module('order', ['vnCore']);
export default ngModule;

View File

@ -194,6 +194,14 @@ vn-main-block {
margin: 0 auto; margin: 0 auto;
} }
vn-tool-bar {
display: flex;
& > * {
margin-right: .6em;
}
}
.vn-list-item { .vn-list-item {
@extend .pad-medium; @extend .pad-medium;
@extend .border-solid-bottom; @extend .border-solid-bottom;
@ -232,5 +240,6 @@ fieldset[disabled] .mdl-textfield .mdl-textfield__label, .mdl-textfield.is-disab
.ellipsize { .ellipsize {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden overflow: hidden;
max-width: 20em
} }

View File

@ -10,5 +10,7 @@ export default {
item: item:
cb => require.ensure([], () => cb(require('item'))), cb => require.ensure([], () => cb(require('item'))),
ticket: ticket:
cb => require.ensure([], () => cb(require('ticket'))) cb => require.ensure([], () => cb(require('ticket'))),
order:
cb => require.ensure([], () => cb(require('order')))
}; };

View File

@ -1,10 +1,9 @@
import ngModule from '../module'; import ngModule from '../module';
class TicketCard { class TicketCard {
constructor($http, $state, $timeout) { constructor($http, $state) {
this.$http = $http; this.$http = $http;
this.$state = $state; this.$state = $state;
this.$timeout = $timeout;
this.ticket = null; this.ticket = null;
} }
@ -25,7 +24,7 @@ class TicketCard {
} }
}, },
{ {
relation: 'ticketTracking', relation: 'tracking',
scope: { scope: {
fields: ['stateFk'], fields: ['stateFk'],
include: { include: {
@ -36,13 +35,11 @@ class TicketCard {
} }
] ]
}; };
this.$http.get(`/ticket/api/Tickets/${this.$state.params.id}?filter=${JSON.stringify(filter)}`) let json = encodeURIComponent(JSON.stringify(filter));
this.$http.get(`/ticket/api/Tickets/${this.$state.params.id}?filter=${json}`)
.then(res => { .then(res => {
if (res.data && res.data.id) { if (res.data)
this.$timeout(() => { this.ticket = res.data;
this.ticket = res.data;
});
}
} }
); );
} }
@ -50,8 +47,11 @@ class TicketCard {
$onInit() { $onInit() {
this._getTicket(); this._getTicket();
} }
reload() {
this._getTicket();
}
} }
TicketCard.$inject = ['$http', '$state', '$timeout']; TicketCard.$inject = ['$http', '$state'];
ngModule.component('vnTicketCard', { ngModule.component('vnTicketCard', {
template: require('./ticket-card.html'), template: require('./ticket-card.html'),

View File

@ -59,9 +59,12 @@
first: $index == 0,last: $index == sale.components.length - 1 first: $index == 0,last: $index == sale.components.length - 1
}" number>{{::sale.quantity * component.value | currency:'€':3}}</td> }" number>{{::sale.quantity * component.value | currency:'€':3}}</td>
</tr> </tr>
<tr ng-if="index.model.count === 0" class="list list-element">
<td colspan="7" style="text-align: center" translate>No results</td>
</tr>
</tbody> </tbody>
</table> </table>
</vn-vertical> </vn-vertical>
<vn-paging margin-large-top vn-one index="index" total="index.model.count"></vn-paging> <vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-card> </vn-card>
</vn-vertical> </vn-vertical>

View File

@ -3,8 +3,8 @@
step-count="10" step-count="10"
steps="[ steps="[
{name: 'Basic data', state: 'ticket.card.data.stepOne'}, {name: 'Basic data', state: 'ticket.card.data.stepOne'},
{name: 'Price gap', state: 'ticket.card.data.stepTwo'}, {name: 'Price difference', state: 'ticket.card.data.stepTwo'},
{name: 'Step 3', state: 'ticket.card.data.stepThree'}]" {name: 'Charge', state: 'ticket.card.data.stepThree'}]"
on-step-change="$ctrl.onStepChange(state)" on-step-change="$ctrl.onStepChange(state)"
on-step-end="$ctrl.onSubmit()"> on-step-end="$ctrl.onSubmit()">
</vn-step-control> </vn-step-control>

View File

@ -1,6 +1,6 @@
<form name="form"> <form name="form">
<vn-card pad-large> <vn-card pad-large>
<vn-title>Basic data</vn-title> <vn-title>Ticket configuration - Basic data</vn-title>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/api/Clients" url="/api/Clients"

View File

@ -1,8 +1,15 @@
<form name="form"> <form name="form">
<vn-card pad-large> <vn-card pad-large>
<vn-title>Step tree</vn-title> <vn-title>Ticket configuration - Charge</vn-title>
<vn-horizontal> <vn-horizontal>
Ticket id {{$ctrl.ticket.id}} <vn-autocomplete vn-one
url="/api/Clients"
label="Charge difference to"
show-field="name"
value-field="id"
field="$ctrl.ticket.clientFk"
initial-data="$ctrl.ticket.clientFk">
</vn-autocomplete>
</vn-horizontal> </vn-horizontal>
</vn-card> </vn-card>
</form> </form>

View File

@ -1,6 +1,6 @@
<form name="form"> <form name="form">
<vn-card pad-large> <vn-card pad-large>
<vn-title>Price gap</vn-title> <vn-title>Ticket configuration - Price difference</vn-title>
<vn-horizontal> <vn-horizontal>
<table class="vn-grid"> <table class="vn-grid">
<thead> <thead>

View File

@ -9,7 +9,7 @@ class Controller {
$onChanges(data) { $onChanges(data) {
if (!this.ticket || !this.ticket.id) return; if (!this.ticket || !this.ticket.id) return;
let query = `/ticket/api/sales/${this.ticket.id}/priceGap`; let query = `/ticket/api/sales/${this.ticket.id}/priceDifference`;
this.$http.get(query).then(res => { this.$http.get(query).then(res => {
if (res.data) if (res.data)
this.ticket.sales = res.data; this.ticket.sales = res.data;

View File

@ -17,7 +17,7 @@
value="{{$ctrl.ticket.client.name}}"> value="{{$ctrl.ticket.client.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="State" <vn-label-value label="State"
value="{{$ctrl.ticket.ticketTracking.state.name}}"> value="{{$ctrl.ticket.tracking.state.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Sales person" <vn-label-value label="Sales person"
value="{{$ctrl.ticket.client.salesPerson.firstName}} {{$ctrl.ticket.client.salesPerson.name}}"> value="{{$ctrl.ticket.client.salesPerson.firstName}} {{$ctrl.ticket.client.salesPerson.name}}">

View File

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

View File

@ -30,7 +30,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="ticket in index.model.instances" <tr ng-repeat="ticket in $ctrl.tickets track by ticket.id"
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable" class="{{::$ctrl.compareDate(ticket.shipped)}} clickable"
ui-sref="ticket.card.summary({id: {{::ticket.id}}})"> ui-sref="ticket.card.summary({id: {{::ticket.id}}})">
<td> <td>
@ -45,7 +45,7 @@
<td translate>{{::ticket.shipped | date:'HH:MM'}}</td> <td translate>{{::ticket.shipped | date:'HH:MM'}}</td>
<td translate>{{::ticket.nickname}}</td> <td translate>{{::ticket.nickname}}</td>
<td translate>{{::ticket.address.province.name}}</td> <td translate>{{::ticket.address.province.name}}</td>
<td translate>{{::ticket.ticketTracking.state.name}}</td> <td translate>{{::ticket.tracking.state.name}}</td>
<td translate>{{::ticket.agencyMode.name}}</td> <td translate>{{::ticket.agencyMode.name}}</td>
<td translate>{{::ticket.warehouse.name}}</td> <td translate>{{::ticket.warehouse.name}}</td>
<td number translate>{{::ticket.refFk | dashIfEmpty}}</td> <td number translate>{{::ticket.refFk | dashIfEmpty}}</td>
@ -62,7 +62,7 @@
</table> </table>
</vn-horizontal> </vn-horizontal>
</vn-card> </vn-card>
<vn-paging index="index" total="index.model.count"></vn-paging> <vn-auto-paging vn-one index="index" total="index.model.count" items="$ctrl.tickets"></vn-auto-paging>
</div> </div>
</div> </div>
<a ui-sref="ticket.create" vn-bind="+" fixed-bottom-right> <a ui-sref="ticket.create" vn-bind="+" fixed-bottom-right>

View File

@ -31,7 +31,10 @@ export default class Controller {
} }
search(index) { search(index) {
index.accept(); this.tickets = [];
index.accept().then(res => {
this.tickets = res.instances;
});
} }
} }

View File

@ -22,6 +22,7 @@ Item: Articulo
Landing: Llegada Landing: Llegada
Landed: F. entrega Landed: F. entrega
Margin: Margen Margin: Margen
More: Más
m³ per unit: m³ por unidad m³ per unit: m³ por unidad
m³ per quantity: m³ por cantidad m³ per quantity: m³ por cantidad
Name: Nombre Name: Nombre
@ -35,6 +36,7 @@ Package type: Tipo de porte
Price: Precio Price: Precio
Price gap: Diferencia de precio Price gap: Diferencia de precio
Quantity: Cantidad Quantity: Cantidad
Remove lines: Borrar lineas
Sale: Lineas del pedido Sale: Lineas del pedido
Sale checked: Control clientes Sale checked: Control clientes
Shipment: Salida Shipment: Salida

View File

@ -1,27 +1,35 @@
<mg-ajax path="/ticket/api/sales/filter" options="vnIndexNonAuto"></mg-ajax> <mg-ajax path="/ticket/api/sales/filter" options="vnIndexNonAuto"></mg-ajax>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Sale checked</vn-title> <vn-title>Sale checked</vn-title>
<table class="vn-grid"> <table class="vn-grid">
<thead> <thead>
<tr> <tr>
<th style="text-align:center" translate>Is checked</th> <th style="text-align:center" translate>Is checked</th>
<th number translate>Item</th> <th number translate>Item</th>
<th translate style="text-align:center">Description</th> <th translate style="text-align:center">Description</th>
<th number translate>Quantity</th> <th number translate>Quantity</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="sale in index.model.instances track by sale.id"> <tr ng-repeat="sale in $ctrl.instances track by sale.id">
<td style="text-align:center!important">
<td style="text-align:center!important"><vn-check style="text-align:center!important" vn-one field="sale.isChecked.isChecked" disabled="true"></vn-check></td> <vn-check style="text-align:center!important"
<td number>{{::sale.itemFk}}</td> vn-one field="sale.isChecked.isChecked"
<td><vn-fetched-tags sale="sale"/></td> disabled="true">
<td number>{{::sale.quantity}}</td> </vn-check>
</tr> </td>
</tbody> <td number>{{::sale.itemFk}}</td>
</table> <td><vn-fetched-tags sale="sale"/></td>
</vn-vertical> <td number>{{::sale.quantity}}</td>
</tr>
<tr ng-if="index.model.count === 0" class="list list-element">
<td colspan="4" style="text-align: center" translate>No results</td>
</tr>
</tbody>
</table>
</vn-vertical>
</vn-card> </vn-card>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>

View File

@ -3,9 +3,32 @@
<vn-card pad-large> <vn-card pad-large>
<vn-vertical> <vn-vertical>
<vn-title>Sale</vn-title> <vn-title>Sale</vn-title>
<vn-tool-bar margin-medium-bottom>
<vn-button
disabled="$ctrl.ticket.tracking.state.alertLevel != 0"
label="Ok"
ng-click="$ctrl.onStateOkClick()">
</vn-button>
<vn-icon-menu
disabled="$ctrl.ticket.tracking.state.alertLevel != 0"
label="State"
url="/ticket/api/States/alertLevelIs0"
on-change="$ctrl.onStateChange(value)">
</vn-icon-menu>
<vn-button
disabled="!$ctrl.isChecked"
ng-click="$ctrl.onRemoveLinesClick()"
vn-tooltip="Remove lines"
tooltip-position="right"
icon="delete">
</vn-button>
</vn-tool-bar>
<table class="vn-grid"> <table class="vn-grid">
<thead> <thead>
<tr> <tr>
<th number>
<vn-multi-check data="index.model.instances"></vn-multi-check>
</th>
<th number translate>Item</th> <th number translate>Item</th>
<th translate style="text-align:center">Description</th> <th translate style="text-align:center">Description</th>
<th number translate>Quantity</th> <th number translate>Quantity</th>
@ -16,6 +39,9 @@
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="sale in index.model.instances track by sale.id"> <tr ng-repeat="sale in index.model.instances track by sale.id">
<td number>
<vn-check field="sale.checked"></vn-check>
</td>
<td <td
pointer pointer
number number
@ -28,10 +54,14 @@
<td number>{{::sale.discount}} %</td> <td number>{{::sale.discount}} %</td>
<td number>{{::sale.quantity * sale.price | currency:'€':2}}</td> <td number>{{::sale.quantity * sale.price | currency:'€':2}}</td>
</tr> </tr>
<tr ng-if="index.model.count === 0" class="list list-element">
<td colspan="6" style="text-align: center" translate>No results</td>
</tr>
</tbody> </tbody>
</table> </table>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="index.model.instances"></vn-auto-paging>
<vn-item-descriptor-popover vn-id="descriptor"> <vn-item-descriptor-popover vn-id="descriptor">
</vn-item-descriptor-popover> </vn-item-descriptor-popover>
</vn-popover> </vn-popover>

View File

@ -2,11 +2,56 @@ import ngModule from '../module';
import FilterTicketList from '../filter-ticket-list'; import FilterTicketList from '../filter-ticket-list';
class Controller extends FilterTicketList { class Controller extends FilterTicketList {
constructor($scope, $timeout, $stateParams) { constructor($scope, $timeout, $stateParams, $http) {
super($scope, $timeout, $stateParams); super($scope, $timeout, $stateParams);
this.$ = $scope; this.$ = $scope;
this.$timeout = $timeout; this.$timeout = $timeout;
this.onOrder('itemFk', 'ASC'); this.onOrder('itemFk', 'ASC');
this.$http = $http;
}
get isChecked() {
let data = this.$.index.model.instances;
if (data)
for (let instance of data)
if (instance.checked)
return true;
return false;
}
onStateOkClick() {
let filter = {where: {code: "OK"}, fields: ["id"]};
let json = encodeURIComponent(JSON.stringify(filter));
this.$http.get(`/ticket/api/States?filter=${json}`).then(res => {
this.onStateChange(res.data[0].id);
});
}
onStateChange(value) {
let params = {ticketFk: this.$state.params.id, stateFk: value};
this.$http.post(`/ticket/api/TicketTrackings`, params).then(() => {
this.card.reload();
});
}
onRemoveLinesClick() {
let lines = {
delete: []
};
let data = this.$.index.model.instances;
if (data)
for (let i = 0; i < data.length;) {
if (data[i].checked) {
lines.delete.push(data[i].id);
data.splice(i, 1);
} else {
i++;
}
}
let query = `/ticket/api/Sales/crudSale`;
this.$http.post(query, lines);
} }
showDescriptor(event, itemFk) { showDescriptor(event, itemFk) {
@ -19,9 +64,15 @@ class Controller extends FilterTicketList {
} }
} }
Controller.$inject = ['$scope', '$timeout', '$state']; Controller.$inject = ['$scope', '$timeout', '$state', '$http'];
ngModule.component('vnTicketSale', { ngModule.component('vnTicketSale', {
template: require('./sale.html'), template: require('./sale.html'),
controller: Controller controller: Controller,
bindings: {
ticket: '<'
},
require: {
card: '^vnTicketCard'
}
}); });

View File

@ -0,0 +1,82 @@
import './sale.js';
describe('Ticket', () => {
describe('Component vnTicketSale', () => {
let $componentController;
let controller;
let $httpBackend;
let $state;
let $scope;
beforeEach(() => {
angular.mock.module('ticket');
});
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_, $rootScope) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$scope = $rootScope.$new();
$scope.index = {model: {instances: [{id: 1}, {id: 2}]}, accept: () => {
return {
then: () => {}
};
}};
$state = _$state_;
$state.params.id = 1;
controller = $componentController('vnTicketSale', {$scope: $scope}, {$state: $state});
}));
describe('isChecked() setter/getter', () => {
it('should set isChecked value to true when one of the instances has the value checked to true', () => {
let lines = [
{checked: false},
{checked: true}
];
$scope.index.model.instances = lines;
expect(controller.isChecked).toBeTruthy();
});
});
describe('onStateOkClick()', () => {
it('should perform a get and then call a function', () => {
let filter = {where: {code: "OK"}, fields: ["id"]};
filter = encodeURIComponent(JSON.stringify(filter));
let res = [{id: 3}];
spyOn(controller, 'onStateChange');
$httpBackend.whenGET(`/ticket/api/States?filter=${filter}`).respond(res);
$httpBackend.expectGET(`/ticket/api/States?filter=${filter}`);
controller.onStateOkClick();
$httpBackend.flush();
expect(controller.onStateChange).toHaveBeenCalledWith(3);
});
});
describe('onStateChange()', () => {
it('should perform a post and then call a function', () => {
$httpBackend.expectPOST(`/ticket/api/TicketTrackings`).respond();
controller.card = {reload: () => {}};
controller.onStateChange(3);
$httpBackend.flush();
});
});
describe('onRemoveLinesClick()', () => {
it('should remove an object of the model if has the attribute cheched true', () => {
$scope.index.model.instances = [{id: 1, checked: true}, {id: 2, checked: false}];
controller.onRemoveLinesClick();
expect($scope.index.model.instances).toEqual([{id: 2, checked: false}]);
});
it('should make a post if an object the model has the attribute cheched true', () => {
$scope.index.model.instances = [{id: 1, checked: false}, {id: 2, checked: false}];
$httpBackend.expectPOST(`/ticket/api/Sales/crudSale`).respond();
controller.onRemoveLinesClick();
$httpBackend.flush();
});
});
});
});

View File

@ -6,7 +6,7 @@
<vn-horizontal class="ticketSummary__data"> <vn-horizontal class="ticketSummary__data">
<vn-one> <vn-one>
<vn-label-value label="State" <vn-label-value label="State"
value="{{$ctrl.summary.ticketTracking.state.name}}"> value="{{$ctrl.summary.tracking.state.name}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Comercial Name" <vn-label-value label="Comercial Name"
value="{{$ctrl.summary.client.salesPerson.firstName}} {{$ctrl.summary.client.salesPerson.name}}"> value="{{$ctrl.summary.client.salesPerson.firstName}} {{$ctrl.summary.client.salesPerson.name}}">

View File

@ -14,6 +14,7 @@ class Controller {
onSubmit() { onSubmit() {
this.$.watcher.submit().then( this.$.watcher.submit().then(
() => { () => {
this.card.reload();
this.$state.go('ticket.card.tracking.index'); this.$state.go('ticket.card.tracking.index');
} }
); );
@ -23,5 +24,8 @@ Controller.$inject = ['$scope', '$state', 'vnApp', '$translate'];
ngModule.component('vnTicketTrackingEdit', { ngModule.component('vnTicketTrackingEdit', {
template: require('./edit.html'), template: require('./edit.html'),
controller: Controller controller: Controller,
require: {
card: '^vnTicketCard'
}
}); });

View File

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

View File

@ -15,7 +15,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="sale in index.model.instances track by sale.id" class="list list-element"> <tr ng-repeat="sale in $ctrl.instances track by sale.id" class="list list-element">
<td number>{{::sale.itemFk}}</td> <td number>{{::sale.itemFk}}</td>
<td><vn-fetched-tags sale="sale"/></td> <td><vn-fetched-tags sale="sale"/></td>
<td number>{{::sale.quantity}}</td> <td number>{{::sale.quantity}}</td>
@ -23,8 +23,12 @@
<td number>{{::sale.volume.volumeTimesQuantity | number:3}}</td> <td number>{{::sale.volume.volumeTimesQuantity | number:3}}</td>
<td number>{{::sale.volume.m3_total | number:3}}</td> <td number>{{::sale.volume.m3_total | number:3}}</td>
</tr> </tr>
<tr ng-if="index.model.count === 0" class="list list-element">
<td colspan="6" style="text-align: center" translate>No results</td>
</tr>
</tbody> </tbody>
</table> </table>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-auto-paging vn-one margin-large-top index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical> </vn-vertical>

View File

@ -433,9 +433,12 @@ gulp.task('docker-build', async () => {
try { try {
await execP('docker rmi dblocal:latest'); await execP('docker rmi dblocal:latest');
} catch (e) {} } catch (e) {}
try {
await execP('docker volume rm data');
} catch (e) {}
log('Building image...'); log('Building image...');
log(await execP('docker build -t dblocal:latest ./services/db > ./services/db/docker.log')); await execP('docker build -t dblocal:latest ./services/db');
}); });
/** /**
@ -469,7 +472,7 @@ gulp.task('docker-start', async () => {
gulp.task('docker-run', async () => { gulp.task('docker-run', async () => {
try { try {
await execP('docker image inspect -f "{{json .Id}}" dblocal'); await execP('docker image inspect -f "{{json .Id}}" dblocal');
await execP('docker run -d --name dblocal -p 3306:3306 dblocal'); await execP('docker run -d --name dblocal --volume data:/data -p 3306:3306 dblocal');
await runSequenceP('docker-wait'); await runSequenceP('docker-wait');
} catch (err) { } catch (err) {
await runSequenceP('docker-build'); await runSequenceP('docker-build');
@ -484,7 +487,7 @@ gulp.task('docker-wait', callback => {
let interval = 1; let interval = 1;
let elapsedTime = 0; let elapsedTime = 0;
let maxInterval = 45 * 60; let maxInterval = 30 * 60;
log('Waiting for MySQL init process...'); log('Waiting for MySQL init process...');
checker(); checker();

View File

@ -1,4 +1,4 @@
module.exports = function(Self) { module.exports = Self => {
Self.remoteMethod('createWithInsurance', { Self.remoteMethod('createWithInsurance', {
description: 'Creates both classification and one insurance', description: 'Creates both classification and one insurance',
accepts: [{ accepts: [{

View File

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

View File

@ -1,4 +1,4 @@
module.exports = function(Self) { module.exports = Self => {
Self.installMethod('filter', filterParams); Self.installMethod('filter', filterParams);
function filterParams(params) { function filterParams(params) {

View File

@ -1,3 +1,3 @@
module.exports = Self => { module.exports = Self => {
require('../methods/creditClassification/createWithInsurance')(Self); require('../methods/credit-classification/createWithInsurance')(Self);
}; };

View File

@ -1,5 +1,5 @@
module.exports = function(Self) { module.exports = function(Self) {
require('../methods/creditInsurance/filter.js')(Self); require('../methods/credit-insurance/filter')(Self);
Self.validateCredit = function(credit) { Self.validateCredit = function(credit) {
return credit >= 0; return credit >= 0;

View File

@ -1,6 +1,6 @@
module.exports = function(Self) { module.exports = function(Self) {
require('../methods/greuge/filter.js')(Self); require('../methods/greuge/filter')(Self);
require('../methods/greuge/sumAmount.js')(Self); require('../methods/greuge/sumAmount')(Self);
Self.validatesLengthOf('description', { Self.validatesLengthOf('description', {
max: 45, max: 45,

View File

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

View File

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

View File

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

View File

@ -1 +1,2 @@
connect.ini connect.ini
docker.log

View File

@ -1,10 +1,12 @@
FROM verdnatura/vn-mysql:latest FROM verdnatura/vn-mysql:latest
ENV MYSQL_ROOT_PASSWORD root
ENV TZ GMT-1 ENV TZ GMT-1
WORKDIR /docker-entrypoint-initdb.d WORKDIR /docker-entrypoint-initdb.d
COPY install/ ./ COPY install ./
RUN chmod -R 777 . RUN chmod -R 777 .
RUN ./install.sh RUN mkdir /data
CMD ./boot.sh RUN chmod 777 /data
CMD ["mysqld"]
#HEALTHCHECK --interval=5s --timeout=10s --retries=200 \ #HEALTHCHECK --interval=5s --timeout=10s --retries=200 \
# CMD mysqladmin ping -h 127.0.0.1 -u root || exit 1 # CMD mysqladmin ping -h 127.0.0.1 -u root || exit 1
EXPOSE 3306 EXPOSE 3306

View File

@ -1,8 +1,26 @@
#!/bin/bash #!/bin/bash
find /var/lib/mysql -type f -exec touch {} \; && service mysql start if [ -d /data/mysql ]; then
cp -R /data/mysql /var/lib
echo "Restored database to default state"
else
# Disable SQL strict mode # Dump structure
mysql -u root -proot -e "SET GLOBAL sql_mode='NO_ENGINE_SUBSTITUTION';" for file in dump/*-*.sql; do
echo "Imported $file"
mysql -u root -proot < $file
done
sleep infinity # Import changes
for file in changes/*/*.sql; do
echo "Imported $file"
mysql -u root -proot < $file
done
# Import fixtures
echo "Imported fixtures.sql"
mysql -u root -proot < dump/fixtures.sql
# Copy dumpted data to volume
cp -R /var/lib/mysql /data
fi

View File

@ -0,0 +1,16 @@
USE `vn`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`warehouse` AS
SELECT
`t`.`id` AS `id`,
`t`.`name` AS `name`,
`t`.`inventario` AS `isInventory`,
`t`.`is_comparative` AS `isComparative`,
`t`.`comisionantes` AS `hasComission`,
`t`.`reserve` AS `hasAvailable`,
`t`.`isManaged` AS `isManaged`
FROM
`vn2008`.`warehouse` `t`;

View File

@ -0,0 +1,32 @@
USE `vn`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `buy` AS
SELECT
`c`.`Id_Compra` AS `id`,
`c`.`Id_Entrada` AS `entryFk`,
`c`.`Id_Article` AS `itemFk`,
`c`.`Cantidad` AS `amount`,
`c`.`Costefijo` AS `buyingValue`,
`c`.`Cantidad` AS `quantity`,
`c`.`Id_Cubo` AS `packageFk`,
`c`.`Etiquetas` AS `stickers`,
`c`.`Portefijo` AS `freightValue`,
`c`.`Embalajefijo` AS `packageValue`,
`c`.`Comisionfija` AS `comissionValue`,
`c`.`Packing` AS `packing`,
`c`.`grouping` AS `grouping`,
`c`.`caja` AS `groupingMode`,
`c`.`Nicho` AS `location`,
`c`.`Tarifa1` AS `price1`,
`c`.`Tarifa2` AS `price2`,
`c`.`Tarifa3` AS `price3`,
`c`.`PVP` AS `minPrice`,
`c`.`Productor` AS `producer`,
`c`.`Vida` AS `printedStickers`,
`c`.`punteo` AS `isChecked`,
`c`.`Novincular` AS `isIgnored`
FROM
`vn2008`.`Compres` `c`;

View File

@ -0,0 +1,30 @@
USE `vn`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`item` AS
SELECT
`t`.`Id_Article` AS `id`,
`t`.`Article` AS `name`,
`t`.`tipo_id` AS `typeFk`,
`t`.`Medida` AS `size`,
`t`.`Color` AS `inkFk`,
`t`.`Categoria` AS `category`,
`t`.`Tallos` AS `stems`,
`t`.`id_origen` AS `originFk`,
`t`.`description` AS `description`,
`t`.`producer_id` AS `producerFk`,
`t`.`Codintrastat` AS `intrastatFk`,
`t`.`offer` AS `isOnOffer`,
`t`.`expenceFk` AS `expenceFk`,
`t`.`bargain` AS `isBargain`,
`t`.`comments` AS `comment`,
`t`.`relevancy` AS `relevancy`,
`t`.`Foto` AS `image`,
`t`.`generic` AS `generic`,
`t`.`iva_group_id` AS `taxClassFk`,
`t`.`pvp` AS `pvp`,
`t`.`min` AS `min`
FROM
`vn2008`.`Articles` `t`;

View File

@ -0,0 +1,22 @@
USE `vn`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`travel` AS
SELECT
`t`.`id` AS `id`,
`t`.`shipment` AS `shipped`,
`t`.`shipment_hour` AS `shipmentHour`,
`t`.`landing` AS `landed`,
`t`.`landing_hour` AS `landingHour`,
`t`.`warehouse_id` AS `warehouseInFk`,
`t`.`warehouse_id_out` AS `warehouseOutFk`,
`t`.`agency_id` AS `agencyFk`,
`t`.`ref` AS `ref`,
`t`.`delivered` AS `isDelivered`,
`t`.`received` AS `isReceived`,
`t`.`m3` AS `m3`,
`t`.`kg` AS `kg`
FROM
`vn2008`.`travel` `t`;

View File

@ -0,0 +1,22 @@
USE `vn`;
DROP function IF EXISTS `getSpecialPrice`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` FUNCTION `getSpecialPrice`(vItemFk int(11),vClientFk int(11)) RETURNS decimal(10,2)
BEGIN
DECLARE price DECIMAL(10,2);
SELECT rate3 INTO price
FROM vn.priceFixed
WHERE itemFk = vItemFk
AND CURDATE() BETWEEN started AND ended ORDER BY created DESC LIMIT 1;
SELECT `value` INTO price
FROM vn.specialPrice
WHERE itemFk = vItemFk
AND clientFk = vClientFk ;
RETURN price;
END$$
DELIMITER ;

View File

@ -0,0 +1,13 @@
USE `vn`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`specialPrice` AS
SELECT
`p`.`Id_PrecioEspecial` AS `id`,
`p`.`Id_Cliente` AS `clientFk`,
`p`.`Id_Article` AS `itemFk`,
`p`.`PrecioEspecial` AS `value`
FROM
`vn2008`.`PreciosEspeciales` `p`;

View File

@ -0,0 +1,11 @@
CREATE TABLE vn.ticketComponentTemplate
SELECT * FROM vn2008.template_bionic_component;
ALTER TABLE `vn`.`ticketComponentTemplate`
CHANGE COLUMN `warehouse_id` `warehouseFk` SMALLINT(5) UNSIGNED NOT NULL ,
CHANGE COLUMN `item_id` `itemFk` INT(11) NOT NULL ,
CHANGE COLUMN `component_id` `componentFk` INT(10) UNSIGNED NOT NULL;

View File

@ -41,13 +41,13 @@ INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`)
(5, 'Holanda', 1, 'NL', 1), (5, 'Holanda', 1, 'NL', 1),
(30,'Francia', 1, 'FR', 1); (30,'Francia', 1, 'FR', 1);
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `isManaged`) INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`)
VALUES VALUES
(1, 'Warehouse One', 0, 1, 1), (1, 'Warehouse One', 0, 1, 1, 1),
(2, 'Warehouse Two', 0, 1, 1), (2, 'Warehouse Two', 0, 1, 1, 1),
(3, 'Warehouse Three', 1, 1, 1), (3, 'Warehouse Three', 1, 1, 1, 1),
(4, 'Warehouse Four', 1, 1, 1), (4, 'Warehouse Four', 1, 1, 1, 1),
(5, 'Warehouse Five', 1, 1, 0); (5, 'Warehouse Five', 1, 1, 1, 0);
INSERT INTO `vn`.`warehouseAlias`(`id`, `name`) INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
VALUES VALUES
@ -600,3 +600,16 @@ INSERT INTO `vn`.`ticketWeekly`(`ticketFk`, `weekDay`)
( 4, 4), ( 4, 4),
( 5, 6); ( 5, 6);
INSERT INTO `vn`.`travel`(`id`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyFk`, `m3`, `kg`)
VALUES
( 1, CURDATE(), 1, 2, 1, 100.00, 1000),
( 2, CURDATE(), 1, 2, 1, 150, 2000),
( 3, CURDATE(), 1, 2, 1, 0.00, 0.00),
( 4, CURDATE(), 1, 2, 1, 50.00, 500);
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `companyFk`)
VALUES
( 1, 1, CURDATE(), 1, 442),
( 2, 2, CURDATE(), 2, 442),
( 3, 1, CURDATE(), 3, 442),
( 4, 2, CURDATE(), 4, 69);

View File

@ -1,27 +0,0 @@
#!/bin/bash
# Start MySQL service
find /var/lib/mysql -type f -exec touch {} \; && service mysql start
# Disable SQL strict mode
mysql -u root -proot -e "SET GLOBAL sql_mode='NO_ENGINE_SUBSTITUTION';"
# Dump structure
for file in dump/*-*.sql; do
echo "Imported $file"
mysql -u root -proot < $file
done
# Import changes
for file in changes/*/*.sql; do
echo "Imported $file"
mysql -u root -proot < $file
done
# Import fixtures
echo "Imported fixtures.sql"
mysql -u root -proot < dump/fixtures.sql
# Remove installation
rm -rf changes dump install.sh

View File

@ -1,3 +1,3 @@
module.exports = function(Self) { module.exports = Self => {
require('../methods/item-barcode/crudItemBarcodes.js')(Self); require('../methods/item-barcode/crudItemBarcodes')(Self);
}; };

View File

@ -1,3 +1,3 @@
module.exports = function(Self) { module.exports = Self => {
require('../methods/item-log/getLog.js')(Self); require('../methods/item-log/getLog')(Self);
}; };

View File

@ -1,3 +1,3 @@
module.exports = function(Self) { module.exports = Self => {
require('../methods/item-niche/crudItemNiches.js')(Self); require('../methods/item-niche/crudItemNiches')(Self);
}; };

View File

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

View File

@ -1,6 +1,6 @@
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('priceGap', { Self.remoteMethod('priceDifference', {
description: 'Returns a sale price gap', description: 'Returns a sale price difference',
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
arg: 'ticketFk', arg: 'ticketFk',
@ -14,12 +14,12 @@ module.exports = Self => {
root: true root: true
}, },
http: { http: {
path: `/:ticketFk/priceGap`, path: `/:ticketFk/priceDifference`,
verb: 'GET' verb: 'GET'
} }
}); });
Self.priceGap = async ticketFk => { Self.priceDifference = async ticketFk => {
let filter = { let filter = {
where: { where: {
ticketFk: ticketFk ticketFk: ticketFk

View File

@ -30,7 +30,7 @@ module.exports = Self => {
fields: ['name'] fields: ['name']
} }
}, { }, {
relation: 'ticketTracking', relation: 'tracking',
scope: { scope: {
fields: ['stateFk'], fields: ['stateFk'],
include: { include: {

View File

@ -57,7 +57,7 @@ module.exports = Self => {
} }
}, },
{ {
relation: 'ticketTracking', relation: 'tracking',
scope: { scope: {
fields: ['stateFk'], fields: ['stateFk'],
include: { include: {

View File

@ -27,10 +27,10 @@ module.exports = function(Self) {
if (crudObject.delete && crudObject.delete.length) { if (crudObject.delete && crudObject.delete.length) {
promises.push(Model.destroyAll({id: {inq: crudObject.delete}}, options)); promises.push(Model.destroyAll({id: {inq: crudObject.delete}}, options));
} }
if (crudObject.create.length) { if (crudObject.create && crudObject.create.length) {
promises.push(Model.create(crudObject.create, options)); promises.push(Model.create(crudObject.create, options));
} }
if (crudObject.update.length) { if (crudObject.update) {
crudObject.update.forEach(toUpdate => { crudObject.update.forEach(toUpdate => {
promises.push(Model.upsert(toUpdate, options)); promises.push(Model.upsert(toUpdate, options));
}); });

View File

@ -1,6 +1,6 @@
const md5 = require('md5'); const md5 = require('md5');
module.exports = function(Self) { module.exports = Self => {
// Validations // Validations
Self.validatesUniquenessOf('name', { Self.validatesUniquenessOf('name', {
@ -42,4 +42,24 @@ module.exports = function(Self) {
return account.name; return account.name;
}; };
/**
* Checks if user has a role.
*
* @param {Integer} userId The user id
* @param {String} role The role name
* @return {Boolean} %true if user has the role, %false otherwise
*/
Self.hasRole = async function(userId, role) {
let result = await Self.rawSql(
`SELECT COUNT(*) AS roleCount
FROM account.user u
JOIN account.roleRole rr ON rr.role = u.role
JOIN account.role r ON r.id = rr.inheritsFrom
WHERE u.id = ?
AND r.name = ?`,
[userId, role]
);
return result[0].roleCount > 0;
};
}; };

View File

@ -2,7 +2,7 @@ var UserError = require('../helpers').UserError;
var getFinalState = require('../helpers').getFinalState; var getFinalState = require('../helpers').getFinalState;
var isMultiple = require('../helpers').isMultiple; var isMultiple = require('../helpers').isMultiple;
module.exports = function(Self) { module.exports = Self => {
Self.validate('isDefaultAddress', isActive, Self.validate('isDefaultAddress', isActive,
{message: 'Unable to default a disabled consignee'} {message: 'Unable to default a disabled consignee'}
); );

View File

@ -1,3 +1,3 @@
module.exports = function(Self) { module.exports = Self => {
Self.defineScope({where: {isManaged: {neq: 0}}}); Self.defineScope({where: {isManaged: {neq: 0}}});
}; };

View File

@ -2,7 +2,7 @@ var UserError = require('../helpers').UserError;
var getFinalState = require('../helpers').getFinalState; var getFinalState = require('../helpers').getFinalState;
var isMultiple = require('../helpers').isMultiple; var isMultiple = require('../helpers').isMultiple;
module.exports = function(Self) { module.exports = Self => {
// Methods // Methods
require('../methods/client/activate')(Self); require('../methods/client/activate')(Self);

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