Merge remote-tracking branch 'upstream/dev' into jgallego

This commit is contained in:
Gerard 2019-02-19 16:12:01 +01:00
commit 927957aed8
50 changed files with 667 additions and 203 deletions

11
Jenkinsfile vendored
View File

@ -17,10 +17,15 @@ pipeline {
steps {
script {
env.COMPOSE_PROJECT_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
env.GIT_COMMITTER_EMAIL = sh(
if (!env.GIT_COMMITTER_EMAIL) {
env.COMMITTER_EMAIL = sh(
script: 'git --no-pager show -s --format="%ae"',
returnStdout: true
).trim()
} else {
env.COMMITTER_EMAIL = env.GIT_COMMITTER_EMAIL;
}
switch (env.BRANCH_NAME) {
case 'master':
@ -39,7 +44,7 @@ pipeline {
break
}
}
echo "Committer: ${env.GIT_COMMITTER_EMAIL}"
sh 'printenv'
}
}
stage('Install') {
@ -143,7 +148,7 @@ pipeline {
}
}
if (!env.GIT_COMMITTER_EMAIL) return
if (!env.COMMITTER_EMAIL) return
try {
mail(
to: env.GIT_COMMITTER_EMAIL,

View File

@ -1,7 +1,8 @@
import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/nightmare';
describe('Ticket Edit sale path', () => {
// #1152 refactor ticket.sale, update price no funciona correctamente.
xdescribe('Ticket Edit sale path', () => {
const nightmare = createNightmare();
beforeAll(() => {
@ -156,8 +157,7 @@ describe('Ticket Edit sale path', () => {
it('should update the price', async() => {
const result = await nightmare
.waitToClick(selectors.ticketSales.firstSalePrice)
.write(selectors.ticketSales.firstSalePriceInput, 5)
.write('body', '\u000d') // simulates enter
.write(selectors.ticketSales.firstSalePriceInput, '5\u000d')
.waitForLastSnackbar();
expect(result).toEqual('Data saved!');
@ -181,8 +181,8 @@ describe('Ticket Edit sale path', () => {
const result = await nightmare
.waitToClick(selectors.ticketSales.firstSaleDiscount)
.wait('vn-textfield[label="Discount"] > div[class="container selected"]') // a function selects the text after it's loaded
.write(selectors.ticketSales.firstSaleDiscountInput, 50)
.write('body', '\u000d') // simulates enter
.write(selectors.ticketSales.firstSaleDiscountInput, '50\u000d')
// .write('body', '\u000d') // simulates enter
.waitForLastSnackbar();
expect(result).toEqual('Data saved!');
@ -318,7 +318,7 @@ describe('Ticket Edit sale path', () => {
it('should go back to the original ticket sales section', async() => {
const url = await nightmare
.waitToClick(selectors.itemsIndex.goBackToModuleIndexButton)
.write(selectors.ticketsIndex.searchTicketInput, 'id:16')
.write(selectors.ticketsIndex.searchTicketInput, '16')
.waitToClick(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
@ -488,7 +488,7 @@ describe('Ticket Edit sale path', () => {
it('should now search for a specific ticket', async() => {
const result = await nightmare
.write(selectors.ticketsIndex.searchTicketInput, 'id:16')
.write(selectors.ticketsIndex.searchTicketInput, '16')
.waitToClick(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countElement(selectors.ticketsIndex.searchResult);
@ -574,7 +574,7 @@ describe('Ticket Edit sale path', () => {
it('should once again search for a specific ticket', async() => {
const result = await nightmare
.write(selectors.ticketsIndex.searchTicketInput, 'id:16')
.write(selectors.ticketsIndex.searchTicketInput, '16')
.waitToClick(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countElement(selectors.ticketsIndex.searchResult);

View File

@ -75,9 +75,9 @@ export default class ArrayModel extends ModelProxy {
});
}
data.sort((a, b) => this.sortFunc(a, b, orderComp));
data = data.sort((a, b) => this.sortFunc(a, b, orderComp));
} else if (typeof order === 'function')
data.sort(order);
data = data.sort(order);
this.skip = skip;

View File

@ -1,13 +1,13 @@
<md-checkbox
aria-label="::$ctrl.label"
md-indeterminate="$ctrl.isIntermediate"
ng-disabled="$ctrl.disabled"
ng-disabled="::$ctrl.disabled"
ng-checked="$ctrl.isChecked"
ng-model="$ctrl.model">
<span translate>{{::$ctrl.label}}</span>
</md-checkbox>
<i class="material-icons"
ng-if="$ctrl.hasInfo"
vn-tooltip="{{$ctrl.info}}">
ng-if="::$ctrl.hasInfo"
vn-tooltip="{{::$ctrl.info}}">
info_outline
</i>

View File

@ -14,4 +14,8 @@ vn-check {
md-checkbox.md-checked .md-icon {
background-color: $color-main;
}
md-checkbox {
margin-bottom: 0
}
}

View File

@ -5,7 +5,7 @@
class="inline-tag ellipsize"
ng-class="::{empty: !fetchedTag.value}"
ng-repeat="fetchedTag in $ctrl.tags track by $index"
vn-tooltip="{{::fetchedTag.name}}: {{::fetchedTag.value}}">
title="{{::fetchedTag.name}}: {{::fetchedTag.value}}">
{{::fetchedTag.value}}
</section>
</vn-auto>

View File

@ -155,7 +155,6 @@ vn-table {
padding: 1.5em;
width: 100%;
box-sizing: border-box;
color: $color-font-secondary;
}
}
vn-autocomplete {

View File

@ -19,7 +19,7 @@ input[type=reset]::-moz-focus-inner {
user-select: none;
}
a , .link{
a, .link{
color: $color-font-link;
text-decoration: none;
}
@ -153,7 +153,7 @@ a.vn-list-item {
}
.vn-list-item {
padding: $pad-medium;
border-bottom: $border-thin solid $color-spacer-light;
border-bottom: $border-thin solid $color-spacer;
display: block;
text-decoration: none;
@ -184,7 +184,6 @@ vn-empty-rows.vn-list-item {
text-align: center;
padding: 1.5em;
box-sizing: border-box;
color: $color-font-secondary;
}
/** START - FORM ELEMENTS DISABLED **/

View File

@ -89,12 +89,33 @@ module.exports = Self => {
filter = {
where: {claimFk: id},
include: [
{relation: 'claimResponsible'},
{relation: 'worker'},
{relation: 'claimDestination'},
{relation: 'claimReason'},
{relation: 'claimResult'},
{relation: 'claimRedelivery'}
{
relation: 'claimResponsible'
},
{
relation: 'worker',
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}
},
{
relation: 'claimDestination'
},
{
relation: 'claimReason'
},
{
relation: 'claimResult'
},
{
relation: 'claimRedelivery'
}
]
};
promises.push(Self.app.models.ClaimDevelopment.find(filter));

View File

@ -37,12 +37,18 @@
ui-sref="claim.card.summary({id: claim.id})">
<vn-td number>{{::claim.id}}</vn-td>
<vn-td expand>
<span class="link" ng-click="$ctrl.showDescriptor($event, claim.client.id)">
<span class="link" ng-click="$ctrl.showClientDescriptor($event, claim.client.id)">
{{::claim.client.name}}
</span>
</vn-td>
<vn-td center>{{::claim.created | date:'dd/MM/yyyy'}}</vn-td>
<vn-td expand>{{::claim.worker.user.nickname}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, claim.worker.user.id)">
{{::claim.worker.user.nickname}}
</span>
</vn-td>
<vn-td>
<span class="chip {{::$ctrl.stateColor(claim)}}">
{{::claim.claimState.description}}
@ -61,7 +67,11 @@
</vn-card>
<vn-pagination model="model"></vn-pagination>
</div>
<vn-client-descriptor-popover vn-id="descriptor"></vn-client-descriptor-popover>
<vn-client-descriptor-popover vn-id="clientDescriptor"></vn-client-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>
<vn-dialog class="dialog-summary"
vn-id="dialog-summary-claim">
<tpl-body>

View File

@ -65,14 +65,22 @@ export default class Controller {
}
}
showDescriptor(event, clientFk) {
this.$.descriptor.clientFk = clientFk;
this.$.descriptor.parent = event.target;
this.$.descriptor.show();
showClientDescriptor(event, clientFk) {
this.$.clientDescriptor.clientFk = clientFk;
this.$.clientDescriptor.parent = event.target;
this.$.clientDescriptor.show();
event.preventDefault();
event.stopImmediatePropagation();
}
showWorkerDescriptor(event, userId) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
preview(event, claim) {
this.claimSelected = claim;
this.$.dialogSummaryClaim.show();

View File

@ -3,7 +3,7 @@
"name": "Claims",
"icon": "icon-claims",
"validations": true,
"dependencies": ["item", "client"],
"dependencies": ["worker", "item", "client"],
"menu": [
{"state": "claim.card.basicData", "icon": "settings"},
{"state": "claim.card.detail", "icon": "icon-details"},

View File

@ -54,7 +54,7 @@
<vn-tr ng-repeat="saleClaimed in $ctrl.summary.salesClaimed">
<vn-td number>
<span
ng-click="$ctrl.showDescriptor($event, saleClaimed.sale.itemFk)"
ng-click="$ctrl.showItemDescriptor($event, saleClaimed.sale.itemFk)"
class="link">
{{saleClaimed.sale.itemFk | zeroFill:6}}
</span>
@ -90,7 +90,13 @@
<vn-td>{{development.claimReason.description}}</vn-td>
<vn-td>{{development.claimResult.description}}</vn-td>
<vn-td>{{development.claimResponsible.description}}</vn-td>
<vn-td>{{development.worker.firstName}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, development.worker.user.id)">
{{::development.worker.user.nickname}}
</span>
</vn-td>
<vn-td>{{development.claimRedelivery.description}}</vn-td>
</vn-tr>
</vn-tbody>
@ -115,7 +121,7 @@
<vn-tr ng-repeat="action in $ctrl.summary.actions">
<vn-td number>
<span
ng-click="$ctrl.showDescriptor($event, action.sale.itemFk)"
ng-click="$ctrl.showItemDescriptor($event, action.sale.itemFk)"
class="link">
{{action.sale.itemFk | zeroFill:6}}
</span>
@ -138,6 +144,10 @@
</vn-horizontal>
</vn-card>
<vn-item-descriptor-popover
vn-id="descriptor"
vn-id="itemDescriptor"
quicklinks="$ctrl.quicklinks">
</vn-item-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>

View File

@ -1,7 +1,7 @@
import ngModule from '../module';
class Controller {
constructor($http, $scope) {
constructor($scope, $http) {
this.$http = $http;
this.$ = $scope;
}
@ -17,8 +17,7 @@ class Controller {
this.getSummary();
}
// Item Descriptor
showDescriptor(event, itemFk) {
showItemDescriptor(event, itemFk) {
this.quicklinks = {
btnThree: {
icon: 'icon-transaction',
@ -28,13 +27,21 @@ class Controller {
tooltip: 'Item diary'
}
};
this.$.descriptor.itemFk = itemFk;
this.$.descriptor.parent = event.target;
this.$.descriptor.show();
this.$.itemDescriptor.itemFk = itemFk;
this.$.itemDescriptor.parent = event.target;
this.$.itemDescriptor.show();
}
showWorkerDescriptor(event, userId) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
}
Controller.$inject = ['$http', '$scope'];
Controller.$inject = ['$scope', '$http'];
ngModule.component('vnClaimSummary', {
template: require('./index.html'),

View File

@ -1,8 +1,10 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const buildFilter = require('vn-loopback/util/filter').buildFilter;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethod('filter', {
Self.remoteMethodCtx('filter', {
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [
@ -16,6 +18,21 @@ module.exports = Self => {
type: ['Object'],
description: 'List of tags to filter with',
http: {source: 'query'}
}, {
arg: 'search',
type: 'String',
description: `If it's and integer searchs by id, otherwise it searchs by name`,
http: {source: 'query'}
}, {
arg: 'categoryFk',
type: 'Integer',
description: 'Category id',
http: {source: 'query'}
}, {
arg: 'typeFk',
type: 'Integer',
description: 'Type id',
http: {source: 'query'}
}
],
returns: {
@ -28,12 +45,34 @@ module.exports = Self => {
}
});
Self.filter = async(filter, tags) => {
Self.filter = async(ctx, filter, tags) => {
let conn = Self.dataSource.connector;
let where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {'i.id': {inq: value}}
: {'i.name': {like: `%${value}%`}};
case 'id':
return {'i.id': value};
case 'description':
return {'i.description': {like: `%${value}%`}};
case 'categoryFk':
return {'ic.id': value};
case 'typeFk':
return {'t.id': value};
}
});
filter = mergeFilters(ctx.args.filter, {where});
let stmt = new ParameterizedSQL(
`SELECT i.id, i.image, i.name, i.description,
i.size, i.tag5, i.value5, i.tag6, i.value6,
i.tag7, i.value7, i.tag8, i.value8, i.isActive,
t.name type, u.nickname userNickname,
t.name type, u.id userId,
intr.description AS intrastat, i.stems,
ori.code AS origin, t.name AS type,
ic.name AS category, i.density, tc.description AS taxClass
@ -48,9 +87,9 @@ module.exports = Self => {
LEFT JOIN taxClass tc ON tc.id = i.taxClassFk`
);
if (tags) {
if (ctx.args.tags) {
let i = 1;
for (let tag of tags) {
for (let tag of ctx.args.tags) {
if (tag.value == null) continue;
let tAlias = `it${i++}`;
stmt.merge({
@ -61,8 +100,7 @@ module.exports = Self => {
});
}
}
stmt.merge(Self.buildSuffix(filter, 'i'));
stmt.merge(conn.makeSuffix(filter));
return Self.rawStmt(stmt);
};
};

View File

@ -4,11 +4,10 @@ describe('item filter()', () => {
it('should return 1 result using filter and tags', async() => {
let filter = {
order: 'isActive ASC, name',
limit: 8,
where: {and: [{typeFk: 2}]}
limit: 8
};
let tags = [{value: 'Gem2', tagFk: 58}];
let result = await app.models.Item.filter(filter, tags);
let result = await app.models.Item.filter({args: {filter: filter, typeFk: 2, tags: tags}});
expect(result.length).toEqual(1);
expect(result[0].id).toEqual(2);

View File

@ -23,7 +23,7 @@
<vn-thead>
<vn-tr>
<vn-th>Date</vn-th>
<vn-th number order="DESC">Id</vn-th>
<vn-th number order="DESC">Ticket/Entry</vn-th>
<vn-th>State</vn-th>
<vn-th>Reference</vn-th>
<vn-th>Client</vn-th>

View File

@ -1,3 +1,4 @@
In: Entrada
Out: Salida
Visible quantity: Cantidad visible
Ticket/Entry: Ticket/Entrada

View File

@ -4,22 +4,20 @@
limit="12"
order="isActive DESC, name, id"
data="items"
auto-load="true">
auto-load="false">
</vn-crud-model>
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-item-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
param-builder="$ctrl.paramBuilder(param, value)"
on-search="$ctrl.onSearch($params)"
vn-focus>
</vn-searchbar>
</vn-card>
</div>
<vn-card margin-medium-v>
<vn-table model="model" show-fields="$ctrl.showFields" vn-uvc="itemIndex">
<vn-table model="model" auto-load="false" show-fields="$ctrl.showFields" vn-uvc="itemIndex">
<vn-thead>
<vn-tr>
<vn-th th-id="picture"></vn-th>
@ -45,14 +43,21 @@
<img
ng-src="{{::$ctrl.imagesPath}}/50x50/{{::item.image}}"
zoom-image="{{::$ctrl.imagesPath}}/1600x900/{{::item.image}}"
ng-click="$ctrl.stopEvent($event)"
on-error-src/>
</vn-td>
<vn-td number>{{::item.id | zeroFill:6}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showItemDescriptor($event, item.id)">
{{::item.id | zeroFill:6}}
</span>
</vn-td>
<vn-td expand>
<vn-fetched-tags
max-length="6"
item="item"
title="item.name">
item="::item"
title="::item.name">
</vn-fetched-tags>
</vn-td>
<vn-td number>{{::item.stems}}</vn-td>
@ -60,13 +65,20 @@
<vn-td>{{::item.category}}</vn-td>
<vn-td>{{::item.intrastat}}</vn-td>
<vn-td>{{::item.origin}}</vn-td>
<vn-td>{{::item.userNickname}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, item.userId)">
{{::item.userNickname}}
</span>
</vn-td>
<vn-td>{{::item.density}}</vn-td>
<vn-td number>{{::item.density}}</vn-td>
<vn-td>{{::item.taxClass}}</vn-td>
<vn-td>
<vn-check
disabled="true"
field="item.isActive">
field="::item.isActive">
</vn-check>
</vn-td>
<vn-td shrink>
@ -103,3 +115,9 @@
question="Do you want to clone this item?"
message="All it's properties will be copied">
</vn-confirm>
<vn-item-descriptor-popover vn-id="itemDescriptor">
</vn-item-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>

View File

@ -16,48 +16,52 @@ class Controller {
};
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {id: value}
: {name: {like: `%${value}%`}};
case 'name':
case 'description':
return {[param]: {like: `%${value}%`}};
case 'id':
case 'typeFk':
return {[param]: value};
}
stopEvent(event) {
event.preventDefault();
event.stopImmediatePropagation();
}
showDescriptor(event, itemFk) {
onSearch(params) {
if (params)
this.$.model.applyFilter(null, params);
else
this.$.model.clear();
}
showItemDescriptor(event, itemFk) {
if (event.defaultPrevented) return;
event.preventDefault();
event.stopPropagation();
this.quicklinks = {
btnThree: {
icon: 'icon-transaction',
state: `item.card.diary({
id: ${itemFk},
warehouseFk: ${this.ticket.warehouseFk},
ticketFk: ${this.ticket.id}
})`,
tooltip: 'Item diary'
}
};
this.$scope.descriptor.itemFk = itemFk;
this.$scope.descriptor.parent = event.target;
this.$scope.descriptor.show();
this.$.itemDescriptor.itemFk = itemFk;
this.$.itemDescriptor.parent = event.target;
this.$.itemDescriptor.show();
}
paramBuilder(param, value) {
switch (param) {
case 'tags':
return {[param]: value};
}
showWorkerDescriptor(event, userId) {
if (event.defaultPrevented) return;
event.preventDefault();
event.stopPropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
cloneItem(event, item) {
event.preventDefault();
event.stopImmediatePropagation();
this.stopEvent(event);
this.itemSelected = item;
this.$.clone.show();
}
@ -75,8 +79,7 @@ class Controller {
}
preview(event, item) {
event.preventDefault();
event.stopImmediatePropagation();
this.stopEvent(event);
this.itemSelected = item;
this.$.preview.show();
}

View File

@ -3,7 +3,7 @@
"name": "Items",
"icon": "inbox",
"validations" : true,
"dependencies": ["client", "ticket"],
"dependencies": ["worker", "client", "ticket"],
"menu": [
{"state": "item.card.data", "icon": "settings"},
{"state": "item.card.tags", "icon": "icon-tags"},

View File

@ -40,6 +40,13 @@
field="filter.typeFk">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Description"
model="filter.description">
</vn-textfield>
</vn-horizontal>
<vn-horizontal ng-repeat="itemTag in filter.tags">
<vn-autocomplete
vn-id="tag"
@ -74,13 +81,6 @@
tabindex="-1">
</vn-icon-button>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Description"
model="filter.description">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-icon-button
vn-bind="+"

View File

@ -111,6 +111,7 @@ module.exports = Self => {
FROM tmp.ticketCalculateItem tci
JOIN vn.item i ON i.id = tci.itemFk
JOIN vn.itemType it ON it.id = i.typeFk
JOIN vn.ink ON ink.id = i.inkFk
JOIN vn.worker w on w.id = it.workerFk`);
// Apply order by tag

View File

@ -19,6 +19,7 @@
initial-data="$ctrl.field"
field="$ctrl.field"
translate-fields="['name']"
order="name"
show-field="name"
value-field="field"
label="Order by">

View File

@ -12,7 +12,9 @@ class Controller {
{way: 'DESC', name: 'Descendant'},
];
this.defaultFieldList = [
{field: 'relevancy DESC, name', name: 'Name'},
{field: 'relevancy DESC, name', name: 'Default'},
{field: 'showOrder, price', name: 'Color'},
{field: 'name', name: 'Name'},
{field: 'price', name: 'Price'}
];
this.fieldList = [];
@ -27,20 +29,18 @@ class Controller {
*/
onDataChange() {
const items = this.$scope.model.data;
const newFilterList = [];
if (!items) return;
this.fieldList = [];
this.fieldList = this.fieldList.concat(this.defaultFieldList);
items.forEach(item => {
// Add new tag filters
item.tags.forEach(itemTag => {
const alreadyAdded = this.fieldList.find(order => {
return order.field == itemTag.tagFk;
const alreadyAdded = newFilterList.findIndex(filter => {
return filter.field == itemTag.tagFk;
});
if (!alreadyAdded) {
this.fieldList.push({
if (alreadyAdded == -1) {
newFilterList.push({
name: itemTag.name,
field: itemTag.tagFk,
isTag: true
@ -48,6 +48,20 @@ class Controller {
}
});
});
// Add default filters - Replaces tags with same name
this.defaultFieldList.forEach(defaultField => {
const index = newFilterList.findIndex(newfield => {
return newfield.name == defaultField.name;
});
if (index > -1)
newFilterList[index] = defaultField;
else
newFilterList.push(defaultField);
});
this.fieldList = newFilterList;
}
/**

View File

@ -17,18 +17,17 @@ describe('Order', () => {
describe('onDataChange()', () => {
it(`should return an object with order params`, () => {
let expectedList = [
{field: 'relevancy DESC, name', name: 'Name'},
{field: 'price', name: 'Price'},
{field: 4, name: 'Length', isTag: true}
];
$scope.model.data = [{id: 1, name: 'My Item', tags: [
{tagFk: 4, name: 'Length'}
{tagFk: 4, name: 'Length'},
{tagFk: 5, name: 'Color'}
]}];
let expectedResult = [{field: 'showOrder, price', name: 'Color'}];
let unexpectedResult = [{tagFk: 5, name: 'Color'}];
controller.onDataChange();
expect(controller.fieldList).toEqual(expectedList);
expect(controller.fieldList.length).toEqual(5);
expect(controller.fieldList).toEqual(jasmine.arrayContaining(expectedResult));
expect(controller.fieldList).not.toEqual(jasmine.arrayContaining(unexpectedResult));
});
});

View File

@ -36,11 +36,17 @@
ui-sref="order.card.summary({id: {{::order.id}}})">
<vn-td number>{{::order.id}}</vn-td>
<vn-td expand>
<span class="link" ng-click="$ctrl.showDescriptor($event, order.clientFk)">
<span class="link" ng-click="$ctrl.showClientDescriptor($event, order.clientFk)">
{{::order.client.name}}
</span>
</vn-td>
<vn-td>{{::order.client.salesPerson.user.nickname}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, order.client.salesPerson.user.id)">
{{::order.client.salesPerson.user.nickname | dashIfEmpty}}
</span>
</vn-td>
<vn-td center>
<vn-check
field="order.isConfirmed"
@ -68,8 +74,12 @@
<vn-float-button icon="add"></vn-float-button>
</a>
<vn-client-descriptor-popover
vn-id="descriptor">
vn-id="clientDescriptor">
</vn-client-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>
<vn-dialog
vn-id="summary"
class="dialog-summary">

View File

@ -2,7 +2,7 @@ import ngModule from '../module';
export default class Controller {
constructor($scope) {
this.$scope = $scope;
this.$ = $scope;
this.ticketSelected = null;
this.filter = {
include: [
@ -51,23 +51,31 @@ export default class Controller {
}
}
showDescriptor(event, clientFk) {
this.$scope.descriptor.clientFk = clientFk;
this.$scope.descriptor.parent = event.target;
this.$scope.descriptor.show();
showClientDescriptor(event, clientFk) {
this.$.clientDescriptor.clientFk = clientFk;
this.$.clientDescriptor.parent = event.target;
this.$.clientDescriptor.show();
event.preventDefault();
event.stopImmediatePropagation();
}
showWorkerDescriptor(event, userId) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
onDescriptorLoad() {
this.$scope.popover.relocate();
this.$.popover.relocate();
}
preview(event, order) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedOrder = order;
this.$scope.summary.show();
this.$.summary.show();
}
}

View File

@ -3,7 +3,7 @@
"name": "Orders",
"icon": "shopping_cart",
"validations": true,
"dependencies": ["item", "ticket"],
"dependencies": ["worker", "item", "ticket"],
"menu": [
{"state": "order.card.basicData", "icon": "settings"},
{"state": "order.card.catalog", "icon": "shopping_cart"},

View File

@ -33,14 +33,15 @@ module.exports = Self => {
e.checked,
i2.name nameBox,
e.itemFk,
w.name nameWorker,
w.firstName,
u.nickname userNickname,
u.id userId,
e.created
FROM
vn.expedition e
LEFT JOIN vn.item i2 ON i2.id = e.itemFk
INNER JOIN vn.item i1 ON i1.id = e.isBox
LEFT JOIN vn.worker w ON w.id = e.workerFk
JOIN account.user u ON u.id = w.id
`);
stmt.merge(Self.buildSuffix(filter, 'e'));

View File

@ -32,6 +32,7 @@ module.exports = Self => {
st.created,
st.workerFk,
u.nickname userNickname,
u.id userId,
ste.name AS state
FROM saleTracking st
JOIN sale s ON s.id = st.saleFk

View File

@ -183,7 +183,8 @@ module.exports = Self => {
ts.stateFk as stateFk,
ts.alertLevel as alertLevel,
ts.code as alertLevelCode,
u.nickname userNickname
u.nickname userNickname,
u.id userId
FROM ticket t
LEFT JOIN address a ON a.id = t.addressFk
LEFT JOIN province p ON p.id = a.provinceFk

View File

@ -33,7 +33,7 @@
<vn-td number>
<span
ng-class="{link: expedition.itemFk}"
ng-click="$ctrl.showDescriptor($event, expedition.itemFk)">
ng-click="$ctrl.showItemDescriptor($event, expedition.itemFk)">
{{expedition.itemFk | zeroFill:6}}
</span>
</vn-td>
@ -41,7 +41,14 @@
<vn-td>{{::expedition.nameBox}}</vn-td>
<vn-td number>{{::expedition.counter}}</vn-td>
<vn-td number>{{::expedition.checked}}</vn-td>
<vn-td>{{::expedition.firstName}} {{::expedition.nameWorker}}</vn-td>
<vn-td>{{::expedition.userNickname}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, expedition.userId)">
{{::expedition.userNickname | dashIfEmpty}}
</span>
</vn-td>
<vn-td>{{::expedition.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
</vn-tr>
</vn-tbody>
@ -51,9 +58,14 @@
</vn-card>
</vn-vertical>
<vn-item-descriptor-popover vn-id="descriptor"
<vn-item-descriptor-popover
vn-id="itemDescriptor"
quicklinks="$ctrl.quicklinks">
</vn-item-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>
<vn-confirm
vn-id="delete-expedition"
on-response="$ctrl.returnDialog(response)"

View File

@ -2,25 +2,25 @@ import ngModule from '../module';
class Controller {
constructor($scope, $stateParams, $http) {
this.$scope = $scope;
this.$ = $scope;
this.$stateParams = $stateParams;
this.$http = $http;
}
deleteExpedition(expedition) {
this.expeditionId = expedition.id;
this.$scope.deleteExpedition.show();
this.$.deleteExpedition.show();
}
returnDialog(response) {
if (response === 'ACCEPT') {
this.$http.delete(`/ticket/api/Expeditions/${this.expeditionId}`).then(
() => this.$scope.model.refresh()
() => this.$.model.refresh()
);
}
}
showDescriptor(event, itemFk) {
showItemDescriptor(event, itemFk) {
if (!itemFk) return;
this.quicklinks = {
btnThree: {
@ -33,13 +33,21 @@ class Controller {
tooltip: 'Item diary',
},
};
this.$scope.descriptor.itemFk = itemFk;
this.$scope.descriptor.parent = event.target;
this.$scope.descriptor.show();
this.$.itemDescriptor.itemFk = itemFk;
this.$.itemDescriptor.parent = event.target;
this.$.itemDescriptor.show();
}
showWorkerDescriptor(event, userId) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
onDescriptorLoad() {
this.$scope.popover.relocate();
this.$.popover.relocate();
}
}

View File

@ -59,7 +59,13 @@
</vn-icon>
</vn-td>
<vn-td number>{{::ticket.id}}</vn-td>
<vn-td>{{::ticket.userNickname | dashIfEmpty}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, ticket.userId)">
{{::ticket.userNickname | dashIfEmpty}}
</span>
</vn-td>
<vn-td>
<span class="chip {{$ctrl.compareDate(ticket.shipped)}}">
{{::ticket.shipped | dateTime: 'dd/MM/yyyy'}}
@ -69,7 +75,7 @@
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showDescriptor($event, ticket.clientFk)">
ng-click="$ctrl.showClientDescriptor($event, ticket.clientFk)">
{{::ticket.nickname}}
</span>
</vn-td>
@ -110,5 +116,9 @@
<vn-ticket-summary ticket="$ctrl.selectedTicket"></vn-ticket-summary>
</tpl-body>
</vn-dialog>
<vn-client-descriptor-popover vn-id="descriptor">
<vn-client-descriptor-popover vn-id="clientDescriptor">
</vn-client-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>

View File

@ -88,12 +88,20 @@ export default class Controller {
return 'alert';
}
showDescriptor(event, clientFk) {
showClientDescriptor(event, clientFk) {
event.preventDefault();
event.stopImmediatePropagation();
this.$.descriptor.clientFk = clientFk;
this.$.descriptor.parent = event.target;
this.$.descriptor.show();
this.$.clientDescriptor.clientFk = clientFk;
this.$.clientDescriptor.parent = event.target;
this.$.clientDescriptor.show();
}
showWorkerDescriptor(event, userId) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
preview(event, ticket) {

View File

@ -14,12 +14,13 @@ describe('Component vnTicketIndex', () => {
}];
beforeEach(() => {
ngModule('worker');
ngModule('client');
ngModule('item');
ngModule('ticket');
});
beforeEach(inject(($compile, $rootScope, $httpBackend, _$window_) => {
beforeEach(inject(($compile, $rootScope, _$window_) => {
$window = _$window_;
$element = $compile('<vn-ticket-index></vn-ticket-index>')($rootScope);
controller = $element.controller('vnTicketIndex');
@ -54,18 +55,18 @@ describe('Component vnTicketIndex', () => {
});
});
describe('showDescriptor()', () => {
it('should show the descriptor popover', () => {
spyOn(controller.$.descriptor, 'show');
describe('showClientDescriptor()', () => {
it('should show the client descriptor popover', () => {
spyOn(controller.$.clientDescriptor, 'show');
let event = new MouseEvent('click', {
view: $window,
bubbles: true,
cancelable: true
});
controller.showDescriptor(event, tickets[0].clientFk);
controller.showClientDescriptor(event, tickets[0].clientFk);
expect(controller.$.descriptor.show).toHaveBeenCalledWith();
expect(controller.$.clientDescriptor.show).toHaveBeenCalledWith();
});
});

View File

@ -35,14 +35,26 @@
<vn-td number>{{::request.id}}</vn-td>
<vn-td expand>{{::request.description}}</vn-td>
<vn-td number>{{::request.created | dateTime: 'dd/MM/yyyy'}}</vn-td>
<vn-td>{{::request.requester.user.nickname}}</vn-td>
<vn-td>{{::request.atender.user.nickname}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, request.requester.user.id)">
{{::request.requester.user.nickname | dashIfEmpty}}
</span>
</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, request.atender.user.id)">
{{::request.atender.user.nickname | dashIfEmpty}}
</span>
</vn-td>
<vn-td number>{{::request.quantity}}</vn-td>
<vn-td number>{{::request.price | currency: 'EUR': 2}}</vn-td>
<vn-td number>
<span
ng-show="::request.saleFk"
ng-click="$ctrl.showDescriptor($event, request.sale)"
ng-click="$ctrl.showItemDescriptor($event, request.sale)"
class="link">
{{request.saleFk | zeroFill:6}}
</span>
@ -69,9 +81,13 @@
</vn-card>
</form>
<vn-item-descriptor-popover
vn-id="descriptor"
vn-id="itemDescriptor"
quicklinks="$ctrl.quicklinks">
</vn-item-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>
<a ui-sref="ticket.card.request.create"
vn-tooltip="New request"
vn-bind="+"

View File

@ -1,9 +1,9 @@
import ngModule from '../../module';
class Controller {
constructor($stateParams, $scope) {
constructor($scope, $stateParams) {
this.$stateParams = $stateParams;
this.$scope = $scope;
this.$ = $scope;
this.filter = {
include: [
{
@ -36,15 +36,15 @@ class Controller {
}
removeLine(index) {
this.$scope.model.remove(index);
this.$scope.watcher.check();
this.$scope.model.save().then(() => {
this.$scope.watcher.notifySaved();
this.$scope.watcher.updateOriginalData();
this.$.model.remove(index);
this.$.watcher.check();
this.$.model.save().then(() => {
this.$.watcher.notifySaved();
this.$.watcher.updateOriginalData();
});
}
// Item Descriptor
showDescriptor(event, sale) {
showItemDescriptor(event, sale) {
this.quicklinks = {
btnThree: {
icon: 'icon-transaction',
@ -55,13 +55,21 @@ class Controller {
tooltip: 'Item diary'
}
};
this.$scope.descriptor.itemFk = sale.itemFk;
this.$scope.descriptor.parent = event.target;
this.$scope.descriptor.show();
this.$.itemDescriptor.itemFk = sale.itemFk;
this.$.itemDescriptor.parent = event.target;
this.$.itemDescriptor.show();
}
showWorkerDescriptor(event, userId) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
}
Controller.$inject = ['$stateParams', '$scope'];
Controller.$inject = ['$scope', '$stateParams'];
ngModule.component('vnTicketRequestIndex', {
template: require('./index.html'),

View File

@ -3,7 +3,7 @@
"name": "Tickets",
"icon": "icon-ticket",
"validations": true,
"dependencies": ["item", "client"],
"dependencies": ["worker", "item", "client"],
"menu": [
{"state": "ticket.card.data.stepOne", "icon": "settings"},
{"state": "ticket.card.sale", "icon": "icon-lines"},

View File

@ -32,7 +32,7 @@
</vn-td>
<vn-td number>
<span
ng-click="$ctrl.showDescriptor($event, sale.itemFk)"
ng-click="$ctrl.showItemDescriptor($event, sale.itemFk)"
class="link">
{{sale.itemFk | zeroFill:6}}
</span>
@ -40,9 +40,12 @@
<vn-td><vn-fetched-tags max-length="6" item="sale.item"/></vn-td>
<vn-td>{{::sale.quantity}}</vn-td>
<vn-td>{{::sale.originalQuantity}}</vn-td>
<vn-td title="{{::sale.firstName}} {{::sale.name}}"
class="ellipsize" style="max-width: 5em">
{{::sale.userNickname}}
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, sale.userId)">
{{::sale.userNickname | dashIfEmpty}}
</span>
</vn-td>
<vn-td>{{::sale.state}}</vn-td>
<vn-td>{{::sale.created | date: 'dd/MM/yyyy HH:mm'}}</vn-td>
@ -53,6 +56,10 @@
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-vertical>
<vn-item-descriptor-popover vn-id="descriptor"
<vn-item-descriptor-popover vn-id="itemDescriptor"
quicklinks="$ctrl.quicklinks">
</vn-item-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>

View File

@ -2,11 +2,11 @@ import ngModule from '../module';
class Controller {
constructor($scope, $stateParams) {
this.$scope = $scope;
this.$ = $scope;
this.$stateParams = $stateParams;
}
showDescriptor(event, itemFk) {
showItemDescriptor(event, itemFk) {
this.quicklinks = {
btnThree: {
icon: 'icon-transaction',
@ -18,13 +18,21 @@ class Controller {
tooltip: 'Item diary',
},
};
this.$scope.descriptor.itemFk = itemFk;
this.$scope.descriptor.parent = event.target;
this.$scope.descriptor.show();
this.$.itemDescriptor.itemFk = itemFk;
this.$.itemDescriptor.parent = event.target;
this.$.itemDescriptor.show();
}
showWorkerDescriptor(event, userId) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
onDescriptorLoad() {
this.$scope.popover.relocate();
this.$.popover.relocate();
}
}

View File

@ -6,7 +6,6 @@
limit="20"
data="trackings">
</vn-crud-model>
<vn-vertical compact>
<vn-card pad-large>
<vn-vertical>
@ -22,7 +21,13 @@
<vn-tbody>
<vn-tr ng-repeat="tracking in trackings">
<vn-td>{{::tracking.state.name}}</vn-td>
<vn-td>{{::tracking.worker.firstName}} {{ticket.worker.name}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, tracking.worker.user.id)">
{{::tracking.worker.user.nickname | dashIfEmpty}}
</span>
</vn-td>
<vn-td>{{::tracking.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
</vn-tr>
</vn-tbody>
@ -34,3 +39,7 @@
<a ui-sref="ticket.card.tracking.edit" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>

View File

@ -1,14 +1,21 @@
import ngModule from '../../module';
class Controller {
constructor($stateParams) {
constructor($scope, $stateParams) {
this.$ = $scope;
this.$stateParams = $stateParams;
this.filter = {
include: [
{
relation: 'worker',
scope: {
fields: ['firstName', 'name']
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
}
}
},
{
@ -20,9 +27,17 @@ class Controller {
]
};
}
showWorkerDescriptor(event, userId) {
event.preventDefault();
event.stopImmediatePropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
}
Controller.$inject = ['$stateParams'];
Controller.$inject = ['$scope', '$stateParams'];
ngModule.component('vnTicketTrackingIndex', {
template: require('./index.html'),

View File

@ -0,0 +1,12 @@
<vn-popover vn-id="popover">
<vn-spinner
ng-if="$ctrl.worker == null"
style="padding: 1em;"
enable="true">
</vn-spinner>
<vn-worker-descriptor
ng-if="$ctrl.worker"
worker="$ctrl.worker"
quicklinks="$ctrl.quicklinks">
</vn-worker-descriptor>
</vn-popover>

View File

@ -0,0 +1,83 @@
import ngModule from '../module';
import Component from 'core/lib/component';
import './style.scss';
class Controller extends Component {
constructor($element, $scope, $http, $timeout, $q) {
super($element, $scope);
this.$timeout = $timeout;
this.$http = $http;
this.$q = $q;
this.worker = null;
}
set userId(id) {
if (id == this._userId) return;
this._userId = id;
this.worker = null;
this.loadData();
}
get userId() {
return this._userId;
}
set quicklinks(value = {}) {
this._quicklinks = Object.assign(value, this._quicklinks);
}
get quicklinks() {
return this._quicklinks;
}
show() {
this.$.popover.parent = this.parent;
this.$.popover.show();
}
loadData() {
let query = `api/Workers/findOne`;
let filter = {
where: {
userFk: this._userId
},
include: [
{
relation: 'user',
scope: {fields: ['name', 'email']}
}, {
relation: 'client',
scope: {fields: ['fi']}
}, {
relation: 'sip',
scope: {fields: ['extension']}
}, {
relation: 'department',
scope: {
include: {
relation: 'department'
}
}
}
]
};
this.$http.get(query, {params: {filter}}).then(res => {
this.worker = res.data;
this.$.$applyAsync(() => {
this.$.popover.relocate();
});
});
}
}
Controller.$inject = ['$element', '$scope', '$http', '$timeout', '$q'];
ngModule.component('vnWorkerDescriptorPopover', {
template: require('./index.html'),
controller: Controller,
bindings: {
userId: '<',
quicklinks: '<'
}
});

View File

@ -0,0 +1,97 @@
import './index.js';
describe('worker Component vnWorkerDescriptorPopover', () => {
let $httpBackend;
let $httpParamSerializer;
let $scope;
let controller;
let $element;
beforeEach(ngModule('worker'));
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
$element = angular.element(`<div></div>`);
$scope = $rootScope.$new();
$scope.popover = {relocate: () => {}, show: () => {}};
controller = $componentController('vnWorkerDescriptorPopover', {$scope, $element});
}));
describe('workerFk()', () => {
it(`should not apply any changes if the received id is the same stored in _workerFk`, () => {
controller.worker = 'I exist!';
controller._userId = 1;
spyOn(controller, 'loadData');
controller.userId = 1;
expect(controller.worker).toEqual('I exist!');
expect(controller._userId).toEqual(1);
expect(controller.loadData).not.toHaveBeenCalled();
});
it(`should set the received id into _workerFk, set the worker to null and then call loadData()`, () => {
controller.worker = `Please don't`;
controller._userId = 1;
spyOn(controller, 'loadData');
controller.userId = 999;
expect(controller.worker).toBeNull();
expect(controller._userId).toEqual(999);
expect(controller.loadData).toHaveBeenCalledWith();
});
});
describe('show()', () => {
it(`should call the show()`, () => {
spyOn(controller.$.popover, 'show');
controller.show();
expect(controller.$.popover.show).toHaveBeenCalledWith();
});
});
describe('loadData()', () => {
it(`should perform a get query to store the worker data into the controller`, () => {
controller.userId = 1;
controller.canceler = null;
let response = {};
let config = {
filter: {
where: {
userFk: controller.userId
},
include: [
{
relation: 'user',
scope: {fields: ['name', 'email']}
}, {
relation: 'client',
scope: {fields: ['fi']}
}, {
relation: 'sip',
scope: {fields: ['extension']}
}, {
relation: 'department',
scope: {
include: {
relation: 'department'
}
}
}
]
}
};
let json = $httpParamSerializer(config);
$httpBackend.whenGET(`api/Workers/findOne?${json}`).respond(response);
$httpBackend.expectGET(`api/Workers/findOne?${json}`);
controller.loadData();
$httpBackend.flush();
expect(controller.worker).toEqual(response);
});
});
});

View File

@ -0,0 +1,11 @@
vn-ticket-descriptor-popover {
vn-ticket-descriptor {
display: block;
width: 16em;
max-height: 28em;
& > vn-card {
margin: 0!important;
}
}
}

View File

@ -4,5 +4,6 @@ import './index/';
import './summary';
import './card';
import './descriptor';
import './descriptor-popover';
import './search-panel';
import './basic-data';

View File

@ -657,8 +657,8 @@ INSERT INTO `vn`.`saleComponent`(`saleFk`, `componentFk`, `value`)
INSERT INTO `vn`.`saleTracking`(`saleFk`, `isChecked`, `created`, `originalQuantity`, `workerFk`, `actionFk`, `id`, `stateFk`)
VALUES
( 1, 0, CURDATE(), 5, 40, 3, 1, 14),
( 1, 1, CURDATE(), 5, 40, 3, 2, 8),
( 1, 0, CURDATE(), 5, 55, 3, 1, 14),
( 1, 1, CURDATE(), 5, 54, 3, 2, 8),
( 2, 1, CURDATE(), 10, 40, 4, 3, 8),
( 3, 1, CURDATE(), 2, 40, 4, 4, 8);