2375 entry lastBuy seccion
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2020-08-26 16:33:47 +02:00
parent d23e3eff76
commit 3a82ef0e06
21 changed files with 539 additions and 158 deletions

View File

@ -0,0 +1,2 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES ('Buy', '*', '*', 'ALLOW', 'ROLE', 'buyer');

View File

@ -2,22 +2,26 @@ import ngModule from '../module';
import template from './smart-table.html'; import template from './smart-table.html';
import './smart-table.scss'; import './smart-table.scss';
/**
* Directive to hide/show selected columns of a table, don't use with rowspan.
*/
directive.$inject = ['$http', '$compile', 'vnApp', '$translate']; directive.$inject = ['$http', '$compile', 'vnApp', '$translate'];
export function directive($http, $compile, vnApp, $translate) { export function directive($http, $compile, vnApp, $translate) {
function getHeaderList($element, $scope) { function getHeaderList($element, $scope) {
let allHeaders = $element[0].querySelectorAll(`vn-th[field], vn-th[th-id]`); let filtrableHeaders = $element[0].querySelectorAll('vn-th[field]');
let headerList = Array.from(allHeaders); let headerList = Array.from(filtrableHeaders);
let ids = []; let ids = [];
let titles = {}; let titles = {};
headerList.forEach(header => { headerList.forEach(header => {
let id = header.getAttribute('th-id') || header.getAttribute('field'); let id = header.getAttribute('field');
ids.push(id); ids.push(id);
titles[id] = header.innerText || id.charAt(0).toUpperCase() + id.slice(1); titles[id] = header.innerText || id.charAt(0).toUpperCase() + id.slice(1);
}); });
$scope.fields = ids; $scope.fields = ids;
$scope.titles = titles; $scope.titles = titles;
$scope.allHeaders = Array.from($element[0].querySelectorAll('vn-th'));
return headerList; return headerList;
} }
@ -38,8 +42,8 @@ export function directive($http, $compile, vnApp, $translate) {
Object.keys(userConfig.configuration).forEach(key => { Object.keys(userConfig.configuration).forEach(key => {
let index; let index;
if (userConfig.configuration[key] === false) { if (userConfig.configuration[key] === false) {
index = headerList.findIndex(el => { index = $scope.allHeaders.findIndex(el => {
return (el.getAttribute('th-id') == key || el.getAttribute('field') == key); return el.getAttribute('field') == key;
}); });
let baseSelector = `vn-table[vn-smart-table=${userConfig.tableCode}] > div`; let baseSelector = `vn-table[vn-smart-table=${userConfig.tableCode}] > div`;

View File

@ -0,0 +1,78 @@
module.exports = Self => {
Self.remoteMethod('editLatestBuys', {
description: 'Updates a column for one of more buys',
accessType: 'WRITE',
accepts: [{
arg: 'column',
type: 'Object',
required: true,
description: `the column to edit and it's new value`
},
{
arg: 'buys',
type: ['Object'],
required: true,
description: `the buys which will be modified`
}],
returns: {
type: 'Object',
root: true
},
http: {
path: `/editLatestBuys`,
verb: 'POST'
}
});
Self.editLatestBuys = async(column, buys) => {
let modelName;
let identifier;
switch (column.field) {
case 'size':
case 'density':
modelName = 'Item';
identifier = 'itemFk';
break;
case 'quantity':
case 'buyingValue':
case 'freightValue':
case 'packing':
case 'grouping':
case 'groupingMode':
case 'comissionValue':
case 'packageValue':
case 'price2':
case 'price3':
case 'minPrice':
case 'weight':
modelName = 'Buy';
identifier = 'id';
}
const models = Self.app.models;
const model = models[modelName];
let tx = await model.beginTransaction({});
try {
let promises = [];
let options = {transaction: tx};
let targets = buys.map(buy => {
return buy[identifier];
});
let value = {};
value[column.field] = column.newValue;
for (let target of targets)
promises.push(model.upsertWithWhere({id: target}, value, options));
await Promise.all(promises);
await tx.commit();
} catch (error) {
await tx.rollback();
throw error;
}
};
};

View File

@ -12,43 +12,44 @@ module.exports = Self => {
arg: 'filter', arg: 'filter',
type: 'Object', type: 'Object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
}, },
{ {
arg: 'search',
type: 'String',
description: `If it's and integer searchs by id, otherwise it searchs by name`,
}, {
arg: 'id',
type: 'Integer',
description: 'Item id',
}, {
arg: 'tags', arg: 'tags',
type: ['Object'], type: ['Object'],
description: 'List of tags to filter with', description: 'List of tags to filter with',
http: {source: 'query'} 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: 'id',
type: 'Integer',
description: 'Item id',
http: {source: 'query'}
}, { }, {
arg: 'categoryFk', arg: 'categoryFk',
type: 'Integer', type: 'Integer',
description: 'Category id', description: 'Category id',
http: {source: 'query'}
}, { }, {
arg: 'typeFk', arg: 'typeFk',
type: 'Integer', type: 'Integer',
description: 'Type id', description: 'Type id',
http: {source: 'query'}
}, { }, {
arg: 'isActive', arg: 'active',
type: 'Boolean', type: 'Boolean',
description: 'Whether the the item is or not active', description: 'Whether the the item is or not active',
http: {source: 'query'} }, {
arg: 'visible',
type: 'Boolean',
description: 'Whether the the item is or not visible',
}, { }, {
arg: 'salesPersonFk', arg: 'salesPersonFk',
type: 'Integer', type: 'Integer',
description: 'The buyer of the item', description: 'The buyer of the item',
http: {source: 'query'} }, {
arg: 'description',
type: 'String',
description: 'The item description',
} }
], ],
returns: { returns: {
@ -64,42 +65,100 @@ module.exports = Self => {
Self.latestBuysFilter = async(ctx, filter) => { Self.latestBuysFilter = async(ctx, filter) => {
let conn = Self.dataSource.connector; let conn = Self.dataSource.connector;
let where = buildFilter(ctx.args, (param, value) => { let where = buildFilter(ctx.args, (param, value) => {
// switch (param) { switch (param) {
// case 'search': case 'search':
// return /^\d+$/.test(value) return /^\d+$/.test(value)
// ? {or: [{'i.id': value}]} ? {'i.id': value}
// : {or: [{'i.name': {like: `%${value}%`}}]}; : {'i.name': {like: `%${value}%`}};
// case 'id': case 'id':
// return {'i.id': value}; return {'i.id': value};
// case 'description': case 'description':
// return {'i.description': {like: `%${value}%`}}; return {'i.description': {like: `%${value}%`}};
// case 'categoryFk': case 'categoryFk':
// return {'ic.id': value}; return {'ic.id': value};
// case 'salesPersonFk': case 'salesPersonFk':
// return {'t.workerFk': value}; return {'it.workerFk': value};
// case 'typeFk': case 'typeFk':
// return {'i.typeFk': value}; return {'i.typeFk': value};
// case 'isActive': case 'active':
// return {'i.isActive': value}; return {'i.isActive': value};
// } case 'visible':
if (value)
return {'v.visible': {gt: 0}};
else if (!value)
return {'v.visible': {lte: 0}};
}
}); });
filter = mergeFilters(ctx.args.filter, {where}); filter = mergeFilters(ctx.args.filter, {where});
let stmts = []; let stmts = [];
let stmt; let stmt;
stmt = new ParameterizedSQL('CALL cache.last_buy_refresh(FALSE)'); stmts.push('CALL cache.last_buy_refresh(FALSE)');
stmts.push(stmt); stmts.push('CALL cache.visible_refresh(@calc_id, FALSE, 1)');
stmt = new ParameterizedSQL(` stmt = new ParameterizedSQL(`
SELECT SELECT
size i.image,
i.id AS itemFk,
i.size,
i.density,
i.typeFk,
t.name AS type,
i.family,
intr.description AS intrastat,
ori.code AS origin,
i.isActive,
b.entryFk,
b.id,
b.quantity,
b.buyingValue,
b.freightValue,
b.isIgnored,
b.packing,
b.grouping,
b.groupingMode,
b.comissionValue,
b.packageValue,
b.price2,
b.price3,
b.minPrice,
b.ektFk,
b.weight
FROM cache.last_buy lb FROM cache.last_buy lb
LEFT JOIN cache.visible v ON v.item_id = lb.item_id
AND v.calc_id = @calc_id
JOIN item i ON i.id = lb.item_id JOIN item i ON i.id = lb.item_id
JOIN itemType it ON it.id = i.typeFk AND lb.warehouse_id = it.warehouseFk JOIN itemType it ON it.id = i.typeFk AND lb.warehouse_id = it.warehouseFk
JOIN buy b ON b.id = lb.buy_id` JOIN buy b ON b.id = lb.buy_id
LEFT JOIN itemCategory ic ON ic.id = it.categoryFk
LEFT JOIN itemType t ON t.id = i.typeFk
LEFT JOIN intrastat intr ON intr.id = i.intrastatFk
LEFT JOIN origin ori ON ori.id = i.originFk`
); );
if (ctx.args.tags) {
let i = 1;
for (const tag of ctx.args.tags) {
const tAlias = `it${i++}`;
if (tag.tagFk) {
stmt.merge({
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
AND ${tAlias}.tagFk = ?
AND ${tAlias}.value LIKE ?`,
params: [tag.tagFk, `%${tag.value}%`],
});
} else {
stmt.merge({
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
AND ${tAlias}.value LIKE ?`,
params: [`%${tag.value}%`],
});
}
}
}
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeSuffix(filter));
let buysIndex = stmts.push(stmt) - 1; let buysIndex = stmts.push(stmt) - 1;

View File

@ -2,6 +2,9 @@
"Entry": { "Entry": {
"dataSource": "vn" "dataSource": "vn"
}, },
"Buy": {
"dataSource": "vn"
},
"EntryLog": { "EntryLog": {
"dataSource": "vn" "dataSource": "vn"
} }

View File

@ -0,0 +1,4 @@
module.exports = Self => {
require('../methods/entry/editLatestBuys')(Self);
require('../methods/entry/latestBuysFilter')(Self);
};

View File

@ -0,0 +1,64 @@
{
"name": "Buy",
"base": "Loggable",
"log": {
"model": "EntryLog",
"relation": "entry"
},
"options": {
"mysql": {
"table": "buy"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"quantity": {
"type": "number"
},
"buyingValue": {
"type": "number"
},
"freightValue": {
"type": "number"
},
"packing": {
"type": "number"
},
"grouping": {
"type": "number"
},
"groupingMode": {
"type": "number"
},
"comissionValue": {
"type": "number"
},
"packageValue": {
"type": "number"
},
"price2": {
"type": "number"
},
"price3": {
"type": "number"
},
"minPrice": {
"type": "number"
},
"weight": {
"type": "number"
}
},
"relations": {
"entry": {
"type": "belongsTo",
"model": "Entry",
"foreignKey": "entryFk",
"required": true
}
}
}

View File

@ -1,5 +1,4 @@
module.exports = Self => { module.exports = Self => {
require('../methods/entry/latestBuysFilter')(Self);
require('../methods/entry/filter')(Self); require('../methods/entry/filter')(Self);
require('../methods/entry/getEntry')(Self); require('../methods/entry/getEntry')(Self);
}; };

View File

@ -10,7 +10,8 @@ class Controller extends ModuleCard {
scope: { scope: {
fields: ['id', 'code'] fields: ['id', 'code']
} }
}, { },
{
relation: 'travel', relation: 'travel',
scope: { scope: {
fields: ['id', 'landed', 'agencyFk', 'warehouseOutFk'], fields: ['id', 'landed', 'agencyFk', 'warehouseOutFk'],
@ -35,12 +36,14 @@ class Controller extends ModuleCard {
} }
] ]
} }
}, { },
{
relation: 'supplier', relation: 'supplier',
scope: { scope: {
fields: ['id', 'nickname'] fields: ['id', 'nickname']
} }
}, { },
{
relation: 'currency' relation: 'currency'
} }
] ]

View File

@ -0,0 +1,3 @@
<slot-descriptor>
<vn-entry-descriptor></vn-entry-descriptor>
</slot-descriptor>

View File

@ -0,0 +1,9 @@
import ngModule from '../module';
import DescriptorPopover from 'salix/components/descriptor-popover';
class Controller extends DescriptorPopover {}
ngModule.vnComponent('vnEntryDescriptorPopover', {
slotTemplate: require('./index.html'),
controller: Controller
});

View File

@ -11,15 +11,23 @@ class Controller extends Descriptor {
} }
get travelFilter() { get travelFilter() {
return this.entry && JSON.stringify({ let travelFilter;
agencyFk: this.entry.travel.agencyFk const entryTravel = this.entry && this.entry.travel;
if (entryTravel && entryTravel.agencyFk) {
travelFilter = this.entry && JSON.stringify({
agencyFk: entryTravel.agencyFk
}); });
} }
return travelFilter;
}
get entryFilter() { get entryFilter() {
if (!this.entry) return null; let entryTravel = this.entry && this.entry.travel;
const date = new Date(this.entry.travel.landed); if (!entryTravel || !entryTravel.landed) return null;
const date = new Date(entryTravel.landed);
date.setHours(0, 0, 0, 0); date.setHours(0, 0, 0, 0);
const from = new Date(date.getTime()); const from = new Date(date.getTime());
@ -35,6 +43,48 @@ class Controller extends Descriptor {
}); });
} }
loadData() {
const filter = {
include: [
{
relation: 'travel',
scope: {
fields: ['id', 'landed', 'agencyFk', 'warehouseOutFk'],
include: [
{
relation: 'agency',
scope: {
fields: ['name']
}
},
{
relation: 'warehouseOut',
scope: {
fields: ['name']
}
},
{
relation: 'warehouseIn',
scope: {
fields: ['name']
}
}
]
}
},
{
relation: 'supplier',
scope: {
fields: ['id', 'nickname']
}
}
]
};
return this.getData(`Entries/${this.id}`, {filter})
.then(res => this.entity = res.data);
}
showEntryReport() { showEntryReport() {
this.vnReport.show('entry-order', { this.vnReport.show('entry-order', {
entryId: this.entry.id entryId: this.entry.id

View File

@ -6,6 +6,7 @@ import './latest-buys';
import './search-panel'; import './search-panel';
import './latest-buys-search-panel'; import './latest-buys-search-panel';
import './descriptor'; import './descriptor';
import './descriptor-popover';
import './card'; import './card';
import './summary'; import './summary';
import './log'; import './log';

View File

@ -3,7 +3,6 @@
<form ng-submit="$ctrl.onSearch()"> <form ng-submit="$ctrl.onSearch()">
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one
label="General search" label="General search"
ng-model="filter.search" ng-model="filter.search"
info="Search items by id, name or barcode" info="Search items by id, name or barcode"
@ -12,7 +11,6 @@
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete
vn-one
vn-focus vn-focus
url="ItemCategories" url="ItemCategories"
label="Category" label="Category"
@ -20,7 +18,7 @@
value-field="id" value-field="id"
ng-model="filter.categoryFk"> ng-model="filter.categoryFk">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete
url="ItemTypes" url="ItemTypes"
label="Type" label="Type"
where="{categoryFk: filter.categoryFk}" where="{categoryFk: filter.categoryFk}"
@ -39,7 +37,6 @@
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete
vn-one
disabled="false" disabled="false"
ng-model="filter.salesPersonFk" ng-model="filter.salesPersonFk"
url="Clients/activeWorkersWithRole" url="Clients/activeWorkersWithRole"
@ -50,6 +47,18 @@
label="Buyer"> label="Buyer">
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-check
label="Is active"
ng-model="filter.active"
triple-state="true">
</vn-check>
<vn-check
label="Is visible"
ng-model="filter.visible"
triple-state="true">
</vn-check>
</vn-horizontal>
<vn-horizontal class="vn-pt-sm"> <vn-horizontal class="vn-pt-sm">
<vn-one class="text-subtitle1" translate> <vn-one class="text-subtitle1" translate>
Tags Tags
@ -65,7 +74,6 @@
<vn-horizontal ng-repeat="itemTag in filter.tags"> <vn-horizontal ng-repeat="itemTag in filter.tags">
<vn-autocomplete <vn-autocomplete
vn-id="tag" vn-id="tag"
vn-one
ng-model="itemTag.tagFk" ng-model="itemTag.tagFk"
data="tags.model" data="tags.model"
show-field="name" show-field="name"
@ -73,14 +81,12 @@
on-change="itemTag.value = null"> on-change="itemTag.value = null">
</vn-autocomplete> </vn-autocomplete>
<vn-textfield <vn-textfield
vn-one
ng-show="tag.selection.isFree !== false" ng-show="tag.selection.isFree !== false"
vn-id="text" vn-id="text"
label="Value" label="Value"
ng-model="itemTag.value"> ng-model="itemTag.value">
</vn-textfield> </vn-textfield>
<vn-autocomplete <vn-autocomplete
vn-one
ng-show="tag.selection.isFree === false" ng-show="tag.selection.isFree === false"
url="{{$ctrl.getSourceTable(tag.selection)}}" url="{{$ctrl.getSourceTable(tag.selection)}}"
label="Value" label="Value"
@ -110,7 +116,6 @@
</vn-horizontal> </vn-horizontal>
<vn-horizontal ng-repeat="fieldFilter in $ctrl.fieldFilters"> <vn-horizontal ng-repeat="fieldFilter in $ctrl.fieldFilters">
<vn-autocomplete <vn-autocomplete
vn-one
label="Field" label="Field"
ng-model="fieldFilter.name" ng-model="fieldFilter.name"
data="$ctrl.moreFields" data="$ctrl.moreFields"

View File

@ -5,7 +5,7 @@ class Controller extends SearchPanel {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);
let model = 'Item'; let model = 'Item';
let moreFields = ['id', 'description', 'name', 'isActive']; let moreFields = ['id', 'description', 'name'];
let properties; let properties;
let validations = window.validations; let validations = window.validations;

View File

@ -1,28 +1,19 @@
<vn-crud-model <vn-crud-model
vn-id="model" vn-id="model"
url="Entries/latestBuysFilter" url="Buys/latestBuysFilter"
limit="20" limit="20"
data="buys" data="$ctrl.buys">
auto-load="true">
</vn-crud-model> </vn-crud-model>
<vn-portal slot="topbar"> <vn-portal slot="topbar">
<vn-searchbar <vn-searchbar
panel="vn-latest-buys-search-panel" panel="vn-latest-buys-search-panel"
suggested-filter="$ctrl.filterParams" placeholder="Search by item id or name"
info="Search buys" info="You can search by item id or name"
filter="$ctrl.filterParams" suggested-filter="{isActive: true}"
model="model" model="model"
auto-state="false"> auto-state="false">
</vn-searchbar> </vn-searchbar>
</vn-portal> </vn-portal>
<!-- <vn-portal slot="topbar">
<vn-searchbar
panel="vn-latest-buys-search-panel"
info="Search buys"
model="model"
auto-state="false">
</vn-searchbar>
</vn-portal> -->
<vn-data-viewer <vn-data-viewer
model="model" model="model"
class="vn-mb-xl vn-w-xl"> class="vn-mb-xl vn-w-xl">
@ -33,72 +24,98 @@
vn-smart-table="latestBuys"> vn-smart-table="latestBuys">
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-th shrink <vn-th shrink>
field='Selection'>
<vn-multi-check <vn-multi-check
model="model"> model="model">
</vn-multi-check> </vn-multi-check>
</vn-th> </vn-th>
<vn-th shrink field='status'></vn-th> <vn-th field="picture">Picture</vn-th>
<vn-th field="id" number>Id</vn-th> <vn-th field="id">Id</vn-th>
<vn-th field="landed" center>Landed</vn-th> <vn-th field="grouping">Grouping</vn-th>
<vn-th>Reference</vn-th> <vn-th field="packing">Packing</vn-th>
<vn-th field="supplierFk">Supplier</vn-th> <vn-th field="size">Size</vn-th>
<vn-th field="currencyFk" center>Currency</vn-th> <vn-th field="type">Type</vn-th>
<vn-th field="companyFk" center>Company</vn-th> <vn-th field="intrastat">Intrastat</vn-th>
<vn-th field="isBooked" center>Booked</vn-th> <vn-th field="origin">Origin</vn-th>
<vn-th field="isConfirmed" center>Confirmed</vn-th> <vn-th field="density">Density</vn-th>
<vn-th field="isOrdered" center>Ordered</vn-th> <vn-th field="isActive">Active</vn-th>
<vn-th>Notes</vn-th> <vn-th field="family">Family</vn-th>
<vn-th field="entryFk">Entry</vn-th>
<vn-th field="quantity">Quantity</vn-th>
<vn-th field="buyingValue">Buying value</vn-th>
<vn-th field="freightValue">Freight value</vn-th>
<vn-th field="comissionValue" expand>Comission value</vn-th>
<vn-th field="packageValue" expand>Package value</vn-th>
<vn-th field="isIgnored">Is ignored</vn-th>
<vn-th field="groupingMode" expand>Grouping mode</vn-th>
<vn-th field="price2">price2</vn-th>
<vn-th field="price3">price3</vn-th>
<vn-th field="minPrice">Min price</vn-th>
<vn-th field="ektFk">Ekt</vn-th>
<vn-th field="weight">Weight</vn-th>
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<a ng-repeat="buy in $ctrl.buys" <a ng-repeat="buy in $ctrl.buys"
class="clickable vn-tr search-result" class="clickable vn-tr search-result"
ui-sref="buy.card.summary({id: {{::buy.id}}})"> ui-sref="entry.card.buy({id: {{::buy.entryFk}}})">
<vn-td shrink> <vn-td shrink>
<vn-check <vn-check
ng-model="buy.checked" ng-model="buy.checked"
vn-click-stop> vn-click-stop>
</vn-check> </vn-check>
</vn-td> </vn-td>
<vn-td shrink> <vn-td shrink >
<vn-icon <img
ng-show="buy.isInventory" ng-src="{{::$root.imagePath}}/catalog/50x50/{{::buy.image}}"
class="bright" zoom-image="{{::$root.imagePath}}/catalog/1600x900/{{::item.image}}"
vn-tooltip="Inventory buy" vn-click-stop
icon="icon-inventory"> on-error-src/>
</vn-icon>
<vn-icon
ng-show="buy.isRaid"
class="bright"
vn-tooltip="Virtual buy"
icon="icon-net">
</vn-icon>
</vn-td> </vn-td>
<vn-td number>{{::buy.size}}</vn-td> <vn-td shrink>
<vn-td center>
<span <span
class="link" vn-click-stop="itemDescriptor.show($event, buy.itemFk)"
vn-click-stop="travelDescriptor.show($event, buy.travelFk)"> class="link">
{{::buy.landed | date:'dd/MM/yyyy'}} {{::buy.itemFk | zeroFill:6}}
</span> </span>
</vn-td> </vn-td>
<vn-td expand>{{::buy.ref}}</vn-td> <vn-td number>{{::buy.grouping}}</vn-td>
<vn-td expand>{{::buy.supplierName}}</vn-td> <vn-td number>{{::buy.packing}}</vn-td>
<vn-td center expand>{{::buy.currencyCode}}</vn-td> <vn-td number>{{::buy.size}}</vn-td>
<vn-td center expand>{{::buy.companyCode}}</vn-td> <vn-td shrink title="{{::buy.type}}">
<vn-td center><vn-check ng-model="buy.isBooked" disabled="true"></vn-check></vn-td> {{::buy.type}}
<vn-td center><vn-check ng-model="buy.isConfirmed" disabled="true"></vn-check></vn-td>
<vn-td center><vn-check ng-model="buy.isOrdered" disabled="true"></vn-check></vn-td>
<vn-td shrink>
<vn-icon
ng-if="buy.notes.length"
vn-tooltip="{{::buy.notes}}"
icon="insert_drive_file"
class="bright">
</vn-icon>
</vn-td> </vn-td>
<vn-td shrink title="{{::item.intrastat}}">
{{::buy.intrastat}}
</vn-td>
<vn-td shrink>{{::buy.origin}}</vn-td>
<vn-td shrink>{{::buy.density}}</vn-td>
<vn-td shrink>
<vn-check
disabled="true"
ng-model="::buy.isActive">
</vn-check>
</vn-td>
<vn-td shrink>{{::buy.family}}</vn-td>
<vn-td shrink>
<span
vn-click-stop="entryDescriptor.show($event, buy.entryFk)"
class="link">
{{::buy.entryFk}}
</span>
</vn-td>
<vn-td number>{{::buy.quantity}}</vn-td>
<vn-td number>{{::buy.buyingValue | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::buy.freightValue | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::buy.comissionValue | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::buy.packageValue | currency: 'EUR':2}}</vn-td>
<vn-td shrink>{{::buy.isIgnored}}</vn-td>
<vn-td shrink>{{::buy.groupingMode}}</vn-td>
<vn-td number>{{::buy.price2 | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::buy.price3 | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::buy.minPrice | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::buy.ektFk | dashIfEmpty}}</vn-td>
<vn-td number>{{::buy.weight}}</vn-td>
</a> </a>
</vn-tbody> </vn-tbody>
</vn-table> </vn-table>
@ -109,12 +126,41 @@
<vn-button class="round sm vn-mb-sm" <vn-button class="round sm vn-mb-sm"
icon="edit" icon="edit"
ng-show="$ctrl.totalChecked > 0" ng-show="$ctrl.totalChecked > 0"
ng-click="$ctrl.edit()" ng-click="edit.show($event)"
vn-tooltip="Edit buys" vn-tooltip="Edit buys"
tooltip-position="left"> tooltip-position="left">
</vn-button> </vn-button>
</vn-vertical> </vn-vertical>
</div> </div>
<vn-travel-descriptor-popover <vn-dialog class="edit"
vn-id="travelDescriptor"> vn-id="edit"
</vn-travel-descriptor-popover> on-accept="$ctrl.onEditAccept()"
message="Edit buy(s)">
<tpl-body>
<vn-horizontal>
<vn-autocomplete
vn-two
ng-model="$ctrl.editedColumn.field"
data="$ctrl.columns"
show-field="displayName"
value-field="field"
label="Field to edit">
</vn-autocomplete>
<vn-textfield
vn-one
label="Value"
ng-model="$ctrl.editedColumn.newValue">
</vn-textfield>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Create</button>
</tpl-buttons>
</vn-dialog>
<vn-item-descriptor-popover
vn-id="itemDescriptor">
</vn-item-descriptor-popover>
<vn-entry-descriptor-popover
vn-id="entryDescriptor">
</vn-entry-descriptor-popover>

View File

@ -8,7 +8,33 @@ export default class Controller extends Section {
id: false, id: false,
actions: false actions: false
}; };
this.editedColumn;
} }
get columns() {
if (this._columns) return this._columns;
this._columns = [
{field: 'quantity', displayName: 'quantity'},
{field: 'buyingValue', displayName: 'buyingValue'},
{field: 'freightValue', displayName: 'freightValue'},
{field: 'packing', displayName: 'packing'},
{field: 'grouping', displayName: 'grouping'},
{field: 'groupingMode', displayName: 'groupingMode'},
{field: 'comissionValue', displayName: 'comissionValue'},
{field: 'packageValue', displayName: 'packageValue'},
{field: 'price2', displayName: 'price2'},
{field: 'price3', displayName: 'price3'},
{field: 'minPrice', displayName: 'minPrice'},
{field: 'weight', displayName: 'weight'},
{field: 'size', displayName: 'size'},
{field: 'density', displayName: 'density'},
{field: 'description', displayName: 'description'}
];
return this._columns;
}
get checked() { get checked() {
const buys = this.$.model.data || []; const buys = this.$.model.data || [];
const checkedBuys = []; const checkedBuys = [];
@ -20,9 +46,36 @@ export default class Controller extends Section {
return checkedBuys; return checkedBuys;
} }
uncheck() {
console.log('clicked!');
const lines = this.checked;
for (let line of lines) {
if (line.checked)
line.checked = false;
}
}
get totalChecked() { get totalChecked() {
return this.checked.length; return this.checked.length;
} }
onEditAccept() {
let data = {
column: this.editedColumn,
buys: this.checked
};
this.$http.post('Buys/editLatestBuys', data)
.then(() => {
this.$.edit.hide();
this.uncheck();
this.$.model.refresh();
});
this.editedColumn = null;
return false;
}
} }
ngModule.component('vnEntryLatestBuys', { ngModule.component('vnEntryLatestBuys', {

View File

@ -2,7 +2,7 @@
"module": "entry", "module": "entry",
"name": "Entries", "name": "Entries",
"icon": "icon-entry", "icon": "icon-entry",
"dependencies": ["travel"], "dependencies": ["travel", "item"],
"validations": true, "validations": true,
"menus": { "menus": {
"main": [ "main": [
@ -25,12 +25,14 @@
"url": "/index?q", "url": "/index?q",
"state": "entry.index", "state": "entry.index",
"component": "vn-entry-index", "component": "vn-entry-index",
"description": "Entries" "description": "Entries",
"acl": ["buyer"]
}, { }, {
"url": "/latest-buys?q", "url": "/latest-buys?q",
"state": "entry.latestBuys", "state": "entry.latestBuys",
"component": "vn-entry-latest-buys", "component": "vn-entry-latest-buys",
"description": "Latest buys" "description": "Latest buys",
"acl": ["buyer"]
}, { }, {
"url": "/:id", "url": "/:id",
"state": "entry.card", "state": "entry.card",

View File

@ -12,42 +12,38 @@ module.exports = Self => {
arg: 'filter', arg: 'filter',
type: 'Object', type: 'Object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'}
}, { }, {
arg: 'tags', arg: 'tags',
type: ['Object'], type: ['Object'],
description: 'List of tags to filter with', description: 'List of tags to filter with',
http: {source: 'query'}
}, { }, {
arg: 'search', arg: 'search',
type: 'String', type: 'String',
description: `If it's and integer searchs by id, otherwise it searchs by name`, description: `If it's and integer searchs by id, otherwise it searchs by name`,
http: {source: 'query'}
}, { }, {
arg: 'id', arg: 'id',
type: 'Integer', type: 'Integer',
description: 'Item id', description: 'Item id',
http: {source: 'query'}
}, { }, {
arg: 'categoryFk', arg: 'categoryFk',
type: 'Integer', type: 'Integer',
description: 'Category id', description: 'Category id',
http: {source: 'query'}
}, { }, {
arg: 'typeFk', arg: 'typeFk',
type: 'Integer', type: 'Integer',
description: 'Type id', description: 'Type id',
http: {source: 'query'}
}, { }, {
arg: 'isActive', arg: 'isActive',
type: 'Boolean', type: 'Boolean',
description: 'Whether the the item is or not active', description: 'Whether the the item is or not active',
http: {source: 'query'}
}, { }, {
arg: 'salesPersonFk', arg: 'salesPersonFk',
type: 'Integer', type: 'Integer',
description: 'The buyer of the item', description: 'The buyer of the item',
http: {source: 'query'} }, {
arg: 'description',
type: 'String',
description: 'The item description',
} }
], ],
returns: { returns: {

View File

@ -11,21 +11,21 @@
vn-smart-table="itemIndex"> vn-smart-table="itemIndex">
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-th th-id="picture" shrink></vn-th> <vn-th field="picture" shrink></vn-th>
<vn-th field="id" shrink>Id</vn-th> <vn-th field="id" shrink>Id</vn-th>
<vn-th th-id="grouping" shrink>Grouping</vn-th> <vn-th field="grouping" shrink>Grouping</vn-th>
<vn-th th-id="packing" shrink>Packing</vn-th> <vn-th field="packing" shrink>Packing</vn-th>
<vn-th th-id="description" style="text-align: center">Description</vn-th> <vn-th field="description" style="text-align: center">Description</vn-th>
<vn-th th-id="stems" shrink>Stems</vn-th> <vn-th field="stems" shrink>Stems</vn-th>
<vn-th th-id="size" shrink>Size</vn-th> <vn-th field="size" shrink>Size</vn-th>
<vn-th th-id="niche" shrink>Niche</vn-th> <vn-th field="niche" shrink>Niche</vn-th>
<vn-th th-id="type" shrink>Type</vn-th> <vn-th field="type" shrink>Type</vn-th>
<vn-th th-id="category" shrink>Category</vn-th> <vn-th field="category" shrink>Category</vn-th>
<vn-th th-id="intrastat" shrink>Intrastat</vn-th> <vn-th field="intrastat" shrink>Intrastat</vn-th>
<vn-th th-id="origin" shrink>Origin</vn-th> <vn-th field="origin" shrink>Origin</vn-th>
<vn-th th-id="salesperson" shrink>Buyer</vn-th> <vn-th field="salesperson" shrink>Buyer</vn-th>
<vn-th th-id="density" shrink>Density</vn-th> <vn-th field="density" shrink>Density</vn-th>
<vn-th th-id="active" shrink>Active</vn-th> <vn-th field="active" shrink>Active</vn-th>
<vn-th></vn-th> <vn-th></vn-th>
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>

View File

@ -14,12 +14,12 @@
</vn-multi-check> </vn-multi-check>
</vn-th> </vn-th>
<vn-th field="id" number>Id</vn-th> <vn-th field="id" number>Id</vn-th>
<vn-th th-id="worker">Worker</vn-th> <vn-th field="worker">Worker</vn-th>
<vn-th th-id="agency">Agency</vn-th> <vn-th field="agency">Agency</vn-th>
<vn-th th-id="vehicle">Vehicle</vn-th> <vn-th field="vehicle">Vehicle</vn-th>
<vn-th th-id="created">Date</vn-th> <vn-th field="created">Date</vn-th>
<vn-th th-id="m3" number></vn-th> <vn-th field="m3" number></vn-th>
<vn-th th-id="description">Description</vn-th> <vn-th field="description">Description</vn-th>
<vn-th shrink></vn-th> <vn-th shrink></vn-th>
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>