Merge pull request '3771-ticket.expedition' (#970) from 3771-ticket.expedition into dev
gitea/salix/pipeline/head This commit looks good Details

Reviewed-on: #970
Reviewed-by: Joan Sanchez <joan@verdnatura.es>
This commit is contained in:
Joan Sanchez 2022-05-13 13:38:35 +00:00
commit 567d5b1ad9
12 changed files with 207 additions and 31 deletions

View File

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

View File

@ -854,18 +854,35 @@ INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPack
('cc', 1640038.00, 56.00, 220.00, 128.00, 1, CURDATE(), 15, 90.00), ('cc', 1640038.00, 56.00, 220.00, 128.00, 1, CURDATE(), 15, 90.00),
('pallet 100', 2745600.00, 100.00, 220.00, 120.00, 1, CURDATE(), 16, 0.00); ('pallet 100', 2745600.00, 100.00, 220.00, 120.00, 1, CURDATE(), 16, 0.00);
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`, `externalId`, `packagingFk`) INSERT INTO `vn`.`expeditionStateType`(`id`, `description`, `code`)
VALUES VALUES
(1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 15, 1, 1, 18, 'UR9000006041', 94), (1, 'En reparto', 'ON DELIVERY'),
(2, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 16, 2, 1, 18, 'UR9000006041', 94), (2, 'Entregada', 'DELIVERED'),
(3, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 3, 1, 18, 'UR9000006041', 94), (3, 'Perdida', 'LOST');
(4, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 4, 1, 18, 'UR9000006041', 94),
(5, 1, 2, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94),
(6, 7, 3, 71, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL, 1, 1, 18, NULL, 94), INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`, `externalId`, `packagingFk`, `stateTypeFk`)
(7, 2, 4, 71, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), NULL, 1, 1, 18, NULL, 94), VALUES
(8, 3, 5, 71, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), NULL, 1, 1, 18, NULL, 94), (1, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 15, 1, 1, 18, 'UR9000006041', 94, 1),
(9, 3, 6, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94), (2, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 16, 2, 1, 18, 'UR9000006041', 94, 1),
(10, 7, 7, 71, NOW(), NULL, 1, 1, 18, NULL, 94); (3, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 3, 1, 18, 'UR9000006041', 94, 2),
(4, 1, 1, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 4, 1, 18, 'UR9000006041', 94, 2),
(5, 1, 2, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94, 3),
(6, 7, 3, 71, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL, 1, 1, 18, NULL, 94, 3),
(7, 2, 4, 71, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), NULL, 1, 1, 18, NULL, 94, NULL),
(8, 3, 5, 71, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), NULL, 1, 1, 18, NULL, 94, 1),
(9, 3, 6, 71, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), NULL, 1, 1, 18, NULL, 94, 2),
(10, 7, 7, 71, NOW(), NULL, 1, 1, 18, NULL, 94, 3);
INSERT INTO `vn`.`expeditionState`(`id`, `created`, `expeditionFk`, `typeFk`, `userFk`)
VALUES
(1, CURDATE(), 1, 1, 1),
(2, CURDATE(), 2, 1, 1),
(3, CURDATE(), 3, 1, 1),
(4, CURDATE(), 3, 2, 1106),
(5, CURDATE(), 5, 1, 1106),
(6, CURDATE(), 5, 3, 1106);
INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, `created`, `pvp`) INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, `created`, `pvp`)
VALUES VALUES

View File

@ -0,0 +1,41 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('filter', {
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [
{
arg: 'filter',
type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'},
},
],
returns: {
type: ['object'],
root: true,
},
http: {
path: `/filter`,
verb: 'GET',
},
});
Self.filter = async(filter, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmt = new ParameterizedSQL(
`SELECT es.created, u.name, u.id workerFk, est.description state
FROM vn.expeditionState es
JOIN vn.expeditionStateType est ON est.id = es.typeFk
JOIN account.user u ON u.id = es.userFk
`);
stmt.merge(Self.buildSuffix(filter, 'es'));
return Self.rawStmt(stmt, myOptions);
};
};

View File

@ -0,0 +1,21 @@
const models = require('vn-loopback/server/server').models;
describe('expeditionState filter()', () => {
it('should return the expedition states matching the filter', async() => {
const tx = await models.ExpeditionState.beginTransaction({});
try {
const options = {transaction: tx};
const filter = {where: {expeditionFk: 5}};
const response = await models.ExpeditionState.filter(filter, options);
expect(response.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -47,9 +47,10 @@ module.exports = Self => {
e.packagingFk, e.packagingFk,
es.workerFk expeditionScanWorkerFk, es.workerFk expeditionScanWorkerFk,
su.name scannerUserName, su.name scannerUserName,
es.scanned es.scanned,
FROM est.description state
vn.expedition e FROM vn.expedition e
LEFT JOIN vn.expeditionStateType est ON est.id = e.stateTypeFk
LEFT JOIN vn.item i2 ON i2.id = e.itemFk LEFT JOIN vn.item i2 ON i2.id = e.itemFk
INNER JOIN vn.item i1 ON i1.id = e.isBox INNER JOIN vn.item i1 ON i1.id = e.isBox
LEFT JOIN vn.packaging p ON p.id = e.packagingFk LEFT JOIN vn.packaging p ON p.id = e.packagingFk

View File

@ -14,6 +14,9 @@
"Expedition": { "Expedition": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ExpeditionState": {
"dataSource": "vn"
},
"Packaging": { "Packaging": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

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

View File

@ -0,0 +1,28 @@
{
"name": "ExpeditionState",
"base": "VnModel",
"options": {
"mysql": {
"table": "expeditionState"
}
},
"properties": {
"id": {
"id": true,
"type": "number",
"description": "Identifier"
},
"created": {
"type": "date"
},
"expeditionFk": {
"type": "number"
},
"typeFk": {
"type": "number"
},
"userFk": {
"type": "number"
}
}
}

View File

@ -19,10 +19,9 @@
<vn-th field="freightItemName">Package type</vn-th> <vn-th field="freightItemName">Package type</vn-th>
<vn-th field="counter" number>Counter</vn-th> <vn-th field="counter" number>Counter</vn-th>
<vn-th field="externalId" number>externalId</vn-th> <vn-th field="externalId" number>externalId</vn-th>
<vn-th field="workerFk">Packager</vn-th>
<vn-th field="created" expand>Created</vn-th> <vn-th field="created" expand>Created</vn-th>
<vn-th field="expeditionScanWorkerFk">Palletizer</vn-th> <vn-th field="state" expand>State</vn-th>
<vn-th field="scanned" expand>Scanned</vn-th> <vn-th></vn-th>
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
@ -33,7 +32,7 @@
vn-tooltip="Delete expedition"> vn-tooltip="Delete expedition">
</vn-icon-button> </vn-icon-button>
</vn-td> </vn-td>
<vn-td number>{{expedition.id | zeroFill:6}}</vn-td> <vn-td number expand>{{expedition.id | zeroFill:6}}</vn-td>
<vn-td number> <vn-td number>
<span <span
ng-class="{link: expedition.packagingItemFk}" ng-class="{link: expedition.packagingItemFk}"
@ -45,20 +44,15 @@
<vn-td>{{::expedition.freightItemName}}</vn-td> <vn-td>{{::expedition.freightItemName}}</vn-td>
<vn-td number>{{::expedition.counter}}</vn-td> <vn-td number>{{::expedition.counter}}</vn-td>
<vn-td expand>{{::expedition.externalId}}</vn-td> <vn-td expand>{{::expedition.externalId}}</vn-td>
<vn-td>
<span
class="link"
ng-click="workerDescriptor.show($event, expedition.workerFk)">
{{::expedition.userName | dashIfEmpty}}
</span>
</vn-td>
<vn-td shrink-datetime>{{::expedition.created | date:'dd/MM/yyyy HH:mm'}}</vn-td> <vn-td shrink-datetime>{{::expedition.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td>{{::expedition.state}}</vn-td>
<vn-td> <vn-td>
<span class="link" ng-click="workerDescriptor.show($event, expedition.expeditionScanWorkerFk)"> <vn-icon-button
{{::expedition.scannerUserName | dashIfEmpty}} vn-click-stop="$ctrl.showLog(expedition)"
</span> vn-tooltip="Status log"
icon="history">
</vn-icon-button>
</vn-td> </vn-td>
<vn-td shrink-datetime>{{::expedition.scanned | date:'dd/MM/yyyy HH:mm'}}</vn-td>
</vn-tr> </vn-tr>
</vn-tbody> </vn-tbody>
</vn-table> </vn-table>
@ -77,4 +71,44 @@
on-accept="$ctrl.onDialogAccept($data)" on-accept="$ctrl.onDialogAccept($data)"
question="Delete expedition" question="Delete expedition"
message="Are you sure you want to delete this expedition?"> message="Are you sure you want to delete this expedition?">
</vn-confirm> </vn-confirm>
<vn-popup vn-id="statusLog">
<vn-crud-model
vn-id="model"
url="ExpeditionStates/filter"
link="{expeditionFk: $ctrl.expedition.id}"
data="expeditionStates"
order="created DESC"
auto-load="true">
</vn-crud-model>
<vn-data-viewer model="model">
<vn-card class="vn-w-md">
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="state">State</vn-th>
<vn-th field="worker">Worker</vn-th>
<vn-th field="created">Created</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="expeditionState in expeditionStates">
<vn-td>{{::expeditionState.state}}</vn-td>
<vn-td expand>
<span
ng-class="{'link': expeditionState.workerFk}"
ng-click="workerDescriptor.show($event, expeditionState.workerFk)">
{{::expeditionState.name || 'System' | translate}}
</span>
</vn-td>
<vn-td shrink-datetime>{{::expeditionState.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-data-viewer>
<vn-worker-descriptor-popover
vn-id="workerDescriptor">
</vn-worker-descriptor-popover>
</vn-popup>

View File

@ -6,6 +6,11 @@ class Controller extends Section {
return this.$http.delete(`Expeditions/${id}`) return this.$http.delete(`Expeditions/${id}`)
.then(() => this.$.model.refresh()); .then(() => this.$.model.refresh());
} }
showLog(expedition) {
this.expedition = expedition;
this.$.statusLog.show();
}
} }
ngModule.vnComponent('vnTicketExpedition', { ngModule.vnComponent('vnTicketExpedition', {

View File

@ -5,10 +5,12 @@ describe('Ticket', () => {
let controller; let controller;
let $scope; let $scope;
let $httpBackend; let $httpBackend;
let $window;
beforeEach(ngModule('ticket')); beforeEach(ngModule('ticket'));
beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => { beforeEach(inject(($componentController, $rootScope, _$httpBackend_, _$window_) => {
$window = _$window_;
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$scope = $rootScope.$new(); $scope = $rootScope.$new();
$scope.model = { $scope.model = {
@ -30,5 +32,23 @@ describe('Ticket', () => {
expect($scope.model.refresh).toHaveBeenCalledWith(); expect($scope.model.refresh).toHaveBeenCalledWith();
}); });
}); });
describe('showLog()', () => {
it('should show the popover status log', () => {
controller.$.statusLog = {show: () => {}};
jest.spyOn(controller.$.statusLog, 'show');
const expedition = {id: 1};
const event = new MouseEvent('click', {
view: $window,
bubbles: true,
cancelable: true
});
controller.showLog(event, expedition);
expect(controller.$.statusLog.show).toHaveBeenCalledWith();
});
});
}); });
}); });

View File

@ -0,0 +1 @@
Status log: Hitorial de estados