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
|
||||
Suppliers: Proveedores
|
||||
Monitors: Monitores
|
||||
Shelvings: Carros
|
||||
|
||||
# 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": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ItemShelvingPlacementSupplyStock": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ItemImageQueue": {
|
||||
"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-search-panel';
|
||||
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
|
||||
History: Historial
|
||||
Botanical: Botánico
|
||||
Shelvings: Carros
|
||||
Barcodes: Códigos de barras
|
||||
Diary: Histórico
|
||||
Item diary: Registro de compra-venta
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
"card": [
|
||||
{"state": "item.card.basicData", "icon": "settings"},
|
||||
{"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.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.diary", "icon": "icon-transaction"},
|
||||
{"state": "item.card.last-entries", "icon": "icon-regentry"},
|
||||
{"state": "item.card.log", "icon": "history"}
|
||||
],
|
||||
"itemType": [
|
||||
|
@ -92,6 +93,16 @@
|
|||
},
|
||||
"acl": ["buyer"]
|
||||
},
|
||||
{
|
||||
"url" : "/shelving",
|
||||
"state": "item.card.shelving",
|
||||
"component": "vn-item-shelving",
|
||||
"description": "Shelvings",
|
||||
"params": {
|
||||
"item": "$ctrl.item"
|
||||
},
|
||||
"acl": ["employee"]
|
||||
},
|
||||
{
|
||||
"url" : "/barcode",
|
||||
"state": "item.card.itemBarcode",
|
||||
|
|
|
@ -13,9 +13,6 @@
|
|||
{"state": "shelving.card.log", "icon": "history"}
|
||||
]
|
||||
},
|
||||
"keybindings": [
|
||||
{"key": "s", "state": "shelving.index"}
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"url": "/shelving",
|
||||
|
|
Loading…
Reference in New Issue