Merge pull request '3095-item.shelving' (!1102) from 3095-item.shelving into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #1102 Reviewed-by: Joan Sanchez <joan@verdnatura.es>
This commit is contained in:
commit
0c73391565
|
@ -1,5 +0,0 @@
|
||||||
ALTER TABLE `vn`.`itemType` CHANGE `transaction` transaction__ tinyint(4) DEFAULT 0 NOT NULL;
|
|
||||||
ALTER TABLE `vn`.`itemType` CHANGE location location__ varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL;
|
|
||||||
ALTER TABLE `vn`.`itemType` CHANGE hasComponents hasComponents__ tinyint(1) DEFAULT 1 NOT NULL;
|
|
||||||
ALTER TABLE `vn`.`itemType` CHANGE warehouseFk warehouseFk__ smallint(6) unsigned DEFAULT 60 NOT NULL;
|
|
||||||
ALTER TABLE `vn`.`itemType` CHANGE compression compression__ decimal(5,2) DEFAULT 1.00 NULL;
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES
|
||||||
|
('ItemShelving', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('ItemShelving', '*', 'WRITE', 'ALLOW', 'ROLE', 'production');
|
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||||
|
VALUES
|
||||||
|
('ItemShelvingPlacementSupplyStock', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
|
|
@ -51,6 +51,7 @@ Entries: Entradas
|
||||||
Users: Usuarios
|
Users: Usuarios
|
||||||
Suppliers: Proveedores
|
Suppliers: Proveedores
|
||||||
Monitors: Monitores
|
Monitors: Monitores
|
||||||
|
Shelvings: Carros
|
||||||
|
|
||||||
# Common
|
# Common
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('deleteItemShelvings', {
|
||||||
|
description: 'Deletes the selected item shelvings',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'itemShelvingIds',
|
||||||
|
type: ['number'],
|
||||||
|
required: true,
|
||||||
|
description: 'The itemShelving ids to delete'
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/deleteItemShelvings`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.deleteItemShelvings = async(itemShelvingIds, options) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const myOptions = {};
|
||||||
|
let tx;
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
if (!myOptions.transaction) {
|
||||||
|
tx = await Self.beginTransaction({});
|
||||||
|
myOptions.transaction = tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const promises = [];
|
||||||
|
for (let itemShelvingId of itemShelvingIds) {
|
||||||
|
const itemShelvingToDelete = models.ItemShelving.destroyById(itemShelvingId, myOptions);
|
||||||
|
promises.push(itemShelvingToDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletedItemShelvings = await Promise.all(promises);
|
||||||
|
|
||||||
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
|
return deletedItemShelvings;
|
||||||
|
} catch (e) {
|
||||||
|
if (tx) await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,21 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
|
describe('ItemShelving deleteItemShelvings()', () => {
|
||||||
|
it('should return the deleted itemShelvings', async() => {
|
||||||
|
const tx = await models.Order.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const itemShelvingIds = [1, 2];
|
||||||
|
const result = await models.ItemShelving.deleteItemShelvings(itemShelvingIds, options);
|
||||||
|
|
||||||
|
expect(result.length).toEqual(2);
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -53,6 +53,9 @@
|
||||||
"ItemShelvingSale": {
|
"ItemShelvingSale": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"ItemShelvingPlacementSupplyStock": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"ItemImageQueue": {
|
"ItemImageQueue": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"name": "ItemShelvingPlacementSupplyStock",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "itemShelvingPlacementSupplyStock"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"itemShelvingFk": {
|
||||||
|
"type": "number",
|
||||||
|
"id": true
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"itemFk": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"longName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"parking": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"shelving": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"packing": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"stock": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/item-shelving/deleteItemShelvings')(Self);
|
||||||
|
};
|
|
@ -24,3 +24,5 @@ import './waste/detail';
|
||||||
import './fixed-price';
|
import './fixed-price';
|
||||||
import './fixed-price-search-panel';
|
import './fixed-price-search-panel';
|
||||||
import './item-type';
|
import './item-type';
|
||||||
|
import './item-shelving';
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
<vn-crud-model
|
||||||
|
vn-id="model"
|
||||||
|
url="ItemShelvingPlacementSupplyStocks"
|
||||||
|
link="{itemFk: $ctrl.$params.id}"
|
||||||
|
data="$ctrl.itemShelvingPlacementSupplyStocks"
|
||||||
|
auto-load="true">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-card>
|
||||||
|
<smart-table
|
||||||
|
model="model"
|
||||||
|
options="$ctrl.smartTableOptions"
|
||||||
|
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||||
|
<slot-actions>
|
||||||
|
<div>
|
||||||
|
<div class="totalBox" style="text-align: center;">
|
||||||
|
<h6 translate>Total</h6>
|
||||||
|
<vn-label-value
|
||||||
|
label="Total labels"
|
||||||
|
value="{{$ctrl.labelTotal.toFixed(2)}}">
|
||||||
|
</vn-label-value>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="vn-pa-md">
|
||||||
|
<vn-button
|
||||||
|
disabled="!$ctrl.checked.length"
|
||||||
|
ng-click="removeConfirm.show()"
|
||||||
|
icon="delete"
|
||||||
|
vn-tooltip="Remove selected lines"
|
||||||
|
vn-acl="replenisherBos">
|
||||||
|
</vn-button>
|
||||||
|
</div>
|
||||||
|
</slot-actions>
|
||||||
|
<slot-table>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th shrink>
|
||||||
|
<vn-multi-check
|
||||||
|
model="model">
|
||||||
|
</vn-multi-check>
|
||||||
|
</th>
|
||||||
|
<th field="created">
|
||||||
|
<span translate>Created</span>
|
||||||
|
</th>
|
||||||
|
<th shrink field="itemFk">
|
||||||
|
<span translate>Item</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
field="longName">
|
||||||
|
<span translate>Concept</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
field="parking">
|
||||||
|
<span translate>Parking</span>
|
||||||
|
</th>
|
||||||
|
<th field="shelving">
|
||||||
|
<span translate>Shelving</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
field="label">
|
||||||
|
<span translate>Etiqueta</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
field="packing"
|
||||||
|
shrink>
|
||||||
|
<span translate>Packing</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
ng-repeat="itemShelvingPlacementSupplyStock in $ctrl.itemShelvingPlacementSupplyStocks"
|
||||||
|
vn-repeat-last on-last="$ctrl.calculateTotals()">
|
||||||
|
<td shrink>
|
||||||
|
<vn-check
|
||||||
|
ng-model="itemShelvingPlacementSupplyStock.checked"
|
||||||
|
vn-click-stop>
|
||||||
|
</vn-check>
|
||||||
|
</td>
|
||||||
|
<td shrink-date>{{::itemShelvingPlacementSupplyStock.created | date: 'dd/MM/yyyy'}}</td>
|
||||||
|
<td>
|
||||||
|
{{::itemShelvingPlacementSupplyStock.itemFk}}
|
||||||
|
</td>
|
||||||
|
<td expand title="{{::itemShelvingPlacementSupplyStock.longName}}">
|
||||||
|
<span
|
||||||
|
vn-click-stop="itemDescriptor.show($event, itemShelvingPlacementSupplyStock.itemFk)"
|
||||||
|
class="link">
|
||||||
|
{{itemShelvingPlacementSupplyStock.longName}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{::itemShelvingPlacementSupplyStock.parking}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{::itemShelvingPlacementSupplyStock.shelving}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{(itemShelvingPlacementSupplyStock.stock / itemShelvingPlacementSupplyStock.packing).toFixed(2)}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{::itemShelvingPlacementSupplyStock.packing}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</slot-table>
|
||||||
|
</smart-table>
|
||||||
|
</vn-card>
|
||||||
|
<vn-item-descriptor-popover
|
||||||
|
vn-id="item-descriptor">
|
||||||
|
</vn-item-descriptor-popover>
|
||||||
|
|
||||||
|
<vn-confirm
|
||||||
|
vn-id="removeConfirm"
|
||||||
|
message="Selected lines will be deleted"
|
||||||
|
question="Are you sure you want to continue?"
|
||||||
|
on-accept="$ctrl.onRemove()">
|
||||||
|
</vn-confirm>
|
|
@ -0,0 +1,89 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
|
export default class Controller extends Section {
|
||||||
|
constructor($element, $) {
|
||||||
|
super($element, $);
|
||||||
|
|
||||||
|
this.smartTableOptions = {
|
||||||
|
activeButtons: {
|
||||||
|
search: true
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
field: 'parking',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Parkings',
|
||||||
|
showField: 'code',
|
||||||
|
valueField: 'code'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'shelving',
|
||||||
|
autocomplete: {
|
||||||
|
url: 'Shelvings',
|
||||||
|
showField: 'code',
|
||||||
|
valueField: 'code'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'created',
|
||||||
|
searchable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'itemFk',
|
||||||
|
searchable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'longName',
|
||||||
|
searchable: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get checked() {
|
||||||
|
const itemShelvings = this.$.model.data || [];
|
||||||
|
const checkedLines = [];
|
||||||
|
for (let itemShelving of itemShelvings) {
|
||||||
|
if (itemShelving.checked)
|
||||||
|
checkedLines.push(itemShelving.itemShelvingFk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkedLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateTotals() {
|
||||||
|
this.labelTotal = 0;
|
||||||
|
const itemShelvings = this.$.model.data || [];
|
||||||
|
itemShelvings.forEach(itemShelving => {
|
||||||
|
const label = itemShelving.stock / itemShelving.packing;
|
||||||
|
this.labelTotal += label;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemove() {
|
||||||
|
const params = {itemShelvingIds: this.checked};
|
||||||
|
const query = `ItemShelvings/deleteItemShelvings`;
|
||||||
|
this.$http.post(query, params)
|
||||||
|
.then(() => {
|
||||||
|
this.vnApp.showSuccess(this.$t('ItemShelvings removed'));
|
||||||
|
this.$.model.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'parking':
|
||||||
|
case 'shelving':
|
||||||
|
case 'label':
|
||||||
|
case 'packing':
|
||||||
|
return {[param]: value};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnItemShelving', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller
|
||||||
|
});
|
|
@ -0,0 +1,81 @@
|
||||||
|
import './index';
|
||||||
|
import crudModel from 'core/mocks/crud-model';
|
||||||
|
|
||||||
|
describe('item shelving', () => {
|
||||||
|
describe('Component vnItemShelving', () => {
|
||||||
|
let controller;
|
||||||
|
let $httpBackend;
|
||||||
|
|
||||||
|
beforeEach(ngModule('item'));
|
||||||
|
|
||||||
|
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
const $element = angular.element('<vn-item-shelving></vn-item-shelving>');
|
||||||
|
controller = $componentController('vnItemShelving', {$element});
|
||||||
|
controller.$.model = crudModel;
|
||||||
|
controller.$.model.data = [
|
||||||
|
{itemShelvingFk: 1, packing: 10, stock: 1},
|
||||||
|
{itemShelvingFk: 2, packing: 12, stock: 5},
|
||||||
|
{itemShelvingFk: 4, packing: 20, stock: 10}
|
||||||
|
];
|
||||||
|
const modelData = controller.$.model.data;
|
||||||
|
modelData[0].checked = true;
|
||||||
|
modelData[1].checked = true;
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('checked() getter', () => {
|
||||||
|
it('should return a the selected rows', () => {
|
||||||
|
const result = controller.checked;
|
||||||
|
|
||||||
|
expect(result).toEqual(expect.arrayContaining([1, 2]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('calculateTotals()', () => {
|
||||||
|
it('should calculate the total of labels', () => {
|
||||||
|
controller.calculateTotals();
|
||||||
|
|
||||||
|
expect(controller.labelTotal).toEqual(1.0166666666666666);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onRemove()', () => {
|
||||||
|
it('shoud remove the selected lines', () => {
|
||||||
|
jest.spyOn(controller.$.model, 'refresh');
|
||||||
|
const expectedParams = {itemShelvingIds: [1, 2]};
|
||||||
|
|
||||||
|
$httpBackend.expectPOST('ItemShelvings/deleteItemShelvings', expectedParams).respond(200);
|
||||||
|
controller.onRemove();
|
||||||
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
expect(controller.$.model.refresh).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('exprBuilder()', () => {
|
||||||
|
it('should search by parking', () => {
|
||||||
|
const expr = controller.exprBuilder('parking', '700-01');
|
||||||
|
|
||||||
|
expect(expr).toEqual({'parking': '700-01'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search by shelving', () => {
|
||||||
|
const expr = controller.exprBuilder('shelving', 'AAA');
|
||||||
|
|
||||||
|
expect(expr).toEqual({'shelving': 'AAA'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search by label', () => {
|
||||||
|
const expr = controller.exprBuilder('label', 0.17);
|
||||||
|
|
||||||
|
expect(expr).toEqual({'label': 0.17});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search by packing', () => {
|
||||||
|
const expr = controller.exprBuilder('packing', 10);
|
||||||
|
|
||||||
|
expect(expr).toEqual({'packing': 10});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
Shelving: Matrícula
|
||||||
|
Remove selected lines: Eliminar líneas seleccionadas
|
||||||
|
Selected lines will be deleted: Las líneas seleccionadas serán eliminadas
|
||||||
|
ItemShelvings removed: Carros eliminados
|
||||||
|
Total labels: Total etiquetas
|
|
@ -54,6 +54,7 @@ Basic data: Datos básicos
|
||||||
Tax: IVA
|
Tax: IVA
|
||||||
History: Historial
|
History: Historial
|
||||||
Botanical: Botánico
|
Botanical: Botánico
|
||||||
|
Shelvings: Carros
|
||||||
Barcodes: Códigos de barras
|
Barcodes: Códigos de barras
|
||||||
Diary: Histórico
|
Diary: Histórico
|
||||||
Item diary: Registro de compra-venta
|
Item diary: Registro de compra-venta
|
||||||
|
|
|
@ -15,11 +15,12 @@
|
||||||
"card": [
|
"card": [
|
||||||
{"state": "item.card.basicData", "icon": "settings"},
|
{"state": "item.card.basicData", "icon": "settings"},
|
||||||
{"state": "item.card.tags", "icon": "icon-tags"},
|
{"state": "item.card.tags", "icon": "icon-tags"},
|
||||||
|
{"state": "item.card.last-entries", "icon": "icon-regentry"},
|
||||||
{"state": "item.card.tax", "icon": "icon-tax"},
|
{"state": "item.card.tax", "icon": "icon-tax"},
|
||||||
{"state": "item.card.botanical", "icon": "local_florist"},
|
{"state": "item.card.botanical", "icon": "local_florist"},
|
||||||
|
{"state": "item.card.shelving", "icon": "icon-inventory"},
|
||||||
{"state": "item.card.itemBarcode", "icon": "icon-barcode"},
|
{"state": "item.card.itemBarcode", "icon": "icon-barcode"},
|
||||||
{"state": "item.card.diary", "icon": "icon-transaction"},
|
{"state": "item.card.diary", "icon": "icon-transaction"},
|
||||||
{"state": "item.card.last-entries", "icon": "icon-regentry"},
|
|
||||||
{"state": "item.card.log", "icon": "history"}
|
{"state": "item.card.log", "icon": "history"}
|
||||||
],
|
],
|
||||||
"itemType": [
|
"itemType": [
|
||||||
|
@ -92,6 +93,16 @@
|
||||||
},
|
},
|
||||||
"acl": ["buyer"]
|
"acl": ["buyer"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url" : "/shelving",
|
||||||
|
"state": "item.card.shelving",
|
||||||
|
"component": "vn-item-shelving",
|
||||||
|
"description": "Shelvings",
|
||||||
|
"params": {
|
||||||
|
"item": "$ctrl.item"
|
||||||
|
},
|
||||||
|
"acl": ["employee"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url" : "/barcode",
|
"url" : "/barcode",
|
||||||
"state": "item.card.itemBarcode",
|
"state": "item.card.itemBarcode",
|
||||||
|
|
|
@ -13,9 +13,6 @@
|
||||||
{"state": "shelving.card.log", "icon": "history"}
|
{"state": "shelving.card.log", "icon": "history"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"keybindings": [
|
|
||||||
{"key": "s", "state": "shelving.index"}
|
|
||||||
],
|
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"url": "/shelving",
|
"url": "/shelving",
|
||||||
|
|
Loading…
Reference in New Issue