Merge branch 'dev' into 4873-zone.delivery-day
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2023-01-12 06:17:58 +00:00
commit 3f7dee63ac
17 changed files with 344 additions and 57 deletions

View File

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [Artículo](Datos Básicos) Añadido campo Unidades/Caja - [Artículo](Datos Básicos) Añadido campo Unidades/Caja
### Changed ### Changed
- [Tickets](Líneas preparadas) Actualizada sección para que sea más visual
### Fixed ### Fixed
- [General] Al utilizar el traductor de Google se descuadraban los iconos - [General] Al utilizar el traductor de Google se descuadraban los iconos

View File

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

View File

@ -1143,10 +1143,10 @@ INSERT INTO `vn`.`itemShelving` (`itemFk`, `shelvingFk`, `visible`, `grouping`,
INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`) INSERT INTO `vn`.`itemShelvingSale` (`itemShelvingFk`, `saleFk`, `quantity`, `created`, `userFk`)
VALUES VALUES
('1', '1', '1', '', '1106'), ('1', '1', '1', util.VN_CURDATE(), '1106'),
('2', '2', '5', '', '1106'), ('2', '2', '5', util.VN_CURDATE(), '1106'),
('1', '7', '1', '', '1106'), ('1', '7', '1', util.VN_CURDATE(), '1106'),
('2', '8', '5', '', '1106'); ('2', '8', '5', util.VN_CURDATE(), '1106');
INSERT INTO `vncontrol`.`accion`(`accion_id`, `accion`) INSERT INTO `vncontrol`.`accion`(`accion_id`, `accion`)
VALUES VALUES

View File

@ -29,7 +29,7 @@ vn-table {
& > tbody { & > tbody {
display: table-row-group; display: table-row-group;
} }
& > vn-tfoot, & > vn-tfoot,
& > .vn-tfoot, & > .vn-tfoot,
& > tfoot { & > tfoot {
border-top: $border; border-top: $border;
@ -42,7 +42,7 @@ vn-table {
height: 48px; height: 48px;
} }
vn-thead, .vn-thead, vn-thead, .vn-thead,
vn-tbody, .vn-tbody, vn-tbody, .vn-tbody,
vn-tfoot, .vn-tfoot, vn-tfoot, .vn-tfoot,
thead, tbody, tfoot { thead, tbody, tfoot {
& > * { & > * {
@ -153,6 +153,18 @@ vn-table {
background-color: $color-font-bg-dark; background-color: $color-font-bg-dark;
color: $color-font-bg; color: $color-font-bg;
} }
&.dark-notice {
background-color: $color-notice;
color: $color-font-bg;
}
&.yellow {
background-color: $color-yellow;
color: $color-font-bg;
}
&.pink {
background-color: $color-pink;
color: $color-font-bg;
}
} }
vn-icon-menu { vn-icon-menu {
display: inline-block; display: inline-block;
@ -194,7 +206,7 @@ vn-table.scrollable > .vn-table,
} }
vn-thead th, vn-thead th,
vn-thead vn-th, vn-thead vn-th,
thead vn-th, thead vn-th,
thead th { thead th {
border-bottom: $border; border-bottom: $border;
@ -217,4 +229,4 @@ vn-table.scrollable.lg,
.tableWrapper { .tableWrapper {
overflow-x: auto; overflow-x: auto;
} }

View File

@ -101,6 +101,8 @@ $color-marginal: #222;
$color-success: #a3d131; $color-success: #a3d131;
$color-notice: #32b1ce; $color-notice: #32b1ce;
$color-alert: #fa3939; $color-alert: #fa3939;
$color-pink: #ff99cc;
$color-yellow: #ffff00;
$color-button: $color-secondary; $color-button: $color-secondary;
$color-spacer: rgba(255, 255, 255, .3); $color-spacer: rgba(255, 255, 255, .3);

View File

@ -11,7 +11,6 @@ describe('InvoiceOut createPdf()', () => {
const ctx = {req: activeCtx}; const ctx = {req: activeCtx};
it('should create a new PDF file and set true the hasPdf property', async() => { it('should create a new PDF file and set true the hasPdf property', async() => {
pending('https://redmine.verdnatura.es/issues/4875');
const invoiceId = 1; const invoiceId = 1;
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx active: activeCtx

View File

@ -13,7 +13,6 @@ describe('InvoiceOut downloadZip()', () => {
}; };
it('should return part of link to dowloand the zip', async() => { it('should return part of link to dowloand the zip', async() => {
pending('https://redmine.verdnatura.es/issues/4875');
const tx = await models.InvoiceOut.beginTransaction({}); const tx = await models.InvoiceOut.beginTransaction({});
try { try {

View File

@ -51,7 +51,6 @@ describe('InvoiceOut filter()', () => {
}); });
it('should return the invoice out matching hasPdf', async() => { it('should return the invoice out matching hasPdf', async() => {
pending('https://redmine.verdnatura.es/issues/4875');
const tx = await models.InvoiceOut.beginTransaction({}); const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
@ -67,7 +66,7 @@ describe('InvoiceOut filter()', () => {
const result = await models.InvoiceOut.filter(ctx, {id: invoiceOut.id}, options); const result = await models.InvoiceOut.filter(ctx, {id: invoiceOut.id}, options);
expect(result.length).toEqual(1); expect(result.length).toBeGreaterThanOrEqual(1);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -0,0 +1,49 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('filter', {
description: 'Returns all item shelving sale matching with the filter',
accessType: 'READ',
accepts: [{
arg: 'filter',
type: 'object',
description: 'Filter defining where and paginated data'
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/filter`,
verb: 'GET'
}
});
Self.filter = async(filter, options) => {
const conn = Self.dataSource.connector;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmt = new ParameterizedSQL(`
SELECT iss.created,
iss.saleFk,
iss.quantity,
iss.userFk,
ish.shelvingFk,
p.code,
u.name
FROM itemShelvingSale iss
LEFT JOIN itemShelving ish ON iss.itemShelvingFk = ish.id
LEFT JOIN shelving s ON ish.shelvingFk = s.code
LEFT JOIN parking p ON s.parkingFk = p.id
LEFT JOIN account.user u ON u.id = iss.userFk`
);
stmt.merge(conn.makeSuffix(filter));
return conn.executeStmt(stmt);
};
};

View File

@ -0,0 +1,3 @@
module.exports = Self => {
require('../methods/item-shelving-sale/filter')(Self);
};

View File

@ -12,21 +12,12 @@
"id": true, "id": true,
"description": "Identifier" "description": "Identifier"
}, },
"shelve": {
"type": "string"
},
"shelvingFk": { "shelvingFk": {
"type": "string" "type": "string"
}, },
"itemFk": { "itemFk": {
"type": "number" "type": "number"
}, },
"deep": {
"type": "number"
},
"quantity": {
"type": "number"
},
"created": { "created": {
"type": "date" "type": "date"
} }
@ -41,6 +32,11 @@
"type": "belongsTo", "type": "belongsTo",
"model": "Account", "model": "Account",
"foreignKey": "userFk" "foreignKey": "userFk"
} },
"shelving": {
"type": "belongsTo",
"model": "Shelving",
"foreignKey": "shelvingFk"
}
} }
} }

View File

@ -0,0 +1,33 @@
module.exports = Self => {
Self.remoteMethodCtx('salePreparingList', {
description: 'Returns a list with the lines of a ticket and its different states of preparation',
accessType: 'READ',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The ticket id',
http: {source: 'path'}
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/:id/salePreparingList`,
verb: 'GET'
}
});
Self.salePreparingList = async(ctx, id, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
query = `CALL vn.salePreparingList(?)`;
const [sales] = await Self.rawSql(query, [id], myOptions);
return sales;
};
};

View File

@ -1,5 +1,6 @@
module.exports = Self => { module.exports = Self => {
require('../methods/sale/getClaimableFromTicket')(Self); require('../methods/sale/getClaimableFromTicket')(Self);
require('../methods/sale/salePreparingList')(Self);
require('../methods/sale/reserve')(Self); require('../methods/sale/reserve')(Self);
require('../methods/sale/deleteSales')(Self); require('../methods/sale/deleteSales')(Self);
require('../methods/sale/updatePrice')(Self); require('../methods/sale/updatePrice')(Self);

View File

@ -1,10 +1,11 @@
<vn-crud-model <vn-crud-model
vn-id="model" vn-id="model"
url="SaleTrackings/listSaleTracking" url="sales"
filter="::$ctrl.filter"
link="{ticketFk: $ctrl.$params.id}" link="{ticketFk: $ctrl.$params.id}"
limit="20" limit="20"
data="sales" data="$ctrl.sales"
order="itemFk DESC" order="concept ASC"
auto-load="true"> auto-load="true">
</vn-crud-model> </vn-crud-model>
<vn-data-viewer model="model"> <vn-data-viewer model="model">
@ -12,31 +13,27 @@
<vn-table model="model"> <vn-table model="model">
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-th shrink></vn-th> <vn-th field="isChecked" center>Is checked</vn-th>
<vn-th field="itemFk" number>Item</vn-th> <vn-th field="itemFk" number>Item</vn-th>
<vn-th expand>Description</vn-th> <vn-th field="concept">Description</vn-th>
<vn-th field="quantity" number>Quantity</vn-th> <vn-th field="quantity" number>Quantity</vn-th>
<vn-th field="originalQuantity" number>Original</vn-th> <vn-th></vn-th>
<vn-th field="workerFk">Worker</vn-th>
<vn-th field="state" shrink>State</vn-th>
<vn-th field="created" expand>Created</vn-th>
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr ng-repeat="sale in sales"> <vn-tr ng-repeat="sale in $ctrl.sales">
<vn-td shrink> <vn-td center>
<vn-icon <span class="chip {{$ctrl.chipHasSaleGroupDetail(sale.preparingList.hasSaleGroupDetail)}} vn-mx-xs chip2" vn-tooltip="has saleGroupDetail"></span>
class="bright" <span class="chip {{$ctrl.chipIsPreviousSelected(sale.preparingList.isPreviousSelected)}} vn-ml-xs" vn-tooltip="is previousSelected"></span>
icon="warning" <span class="chip {{$ctrl.chipIsPrevious(sale.preparingList.isPrevious)}} vn-mr-xs" vn-tooltip="is previous"></span>
ng-if="sale.quantity != sale.originalQuantity" <span class="chip {{$ctrl.chipIsPrepared(sale.preparingList.isPrepared)}} vn-mx-xs" vn-tooltip="is prepared"></span>
vn-tooltip="The quantity do not match"> <span class="chip {{$ctrl.chipIsControled(sale.preparingList.isControled)}} vn-mx-xs" vn-tooltip="is controled"></span>
</vn-icon>
</vn-td> </vn-td>
<vn-td number> <vn-td number>
<span <span
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id)" ng-click="$ctrl.showItemDescriptor($event, sale)"
class="link"> class="link">
{{sale.itemFk | zeroFill:6}} {{::sale.itemFk | zeroFill:6}}
</span> </span>
</vn-td> </vn-td>
<vn-td vn-fetched-tags> <vn-td vn-fetched-tags>
@ -53,16 +50,18 @@
</vn-fetched-tags> </vn-fetched-tags>
</vn-td> </vn-td>
<vn-td number>{{::sale.quantity}}</vn-td> <vn-td number>{{::sale.quantity}}</vn-td>
<vn-td number>{{::sale.originalQuantity}}</vn-td> <vn-td actions>
<vn-td expand> <vn-icon-button
<span vn-click-stop="$ctrl.showSaleTracking(sale)"
class="link" vn-tooltip="Sale tracking"
ng-click="workerDescriptor.show($event, sale.workerFk)"> icon="history">
{{::sale.userNickname | dashIfEmpty}} </vn-icon-button>
</span> <vn-icon-button
vn-click-stop="$ctrl.showItemShelvingSale(sale)"
vn-tooltip="ItemShelvings sale"
icon="icon-inventory">
</vn-icon-button>
</vn-td> </vn-td>
<vn-td shrink>{{::sale.state}}</vn-td>
<vn-td expand>{{::sale.created | date: 'dd/MM/yyyy HH:mm'}}</vn-td>
</vn-tr> </vn-tr>
</vn-tbody> </vn-tbody>
</vn-table> </vn-table>
@ -70,8 +69,99 @@
</vn-data-viewer> </vn-data-viewer>
<vn-item-descriptor-popover <vn-item-descriptor-popover
vn-id="item-descriptor" vn-id="item-descriptor"
warehouse-fk="$ctrl.ticket.warehouseFk"> warehouse-fk="$ctrl.ticket.warehouseFk"
ticket-fk="$ctrl.ticket.id">
</vn-item-descriptor-popover> </vn-item-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="worker-descriptor"> <vn-popup vn-id="saleTracking">
</vn-worker-descriptor-popover> <vn-crud-model
vn-id="modelSaleTracking"
url="SaleTrackings/listSaleTracking"
link="{saleFk: $ctrl.saleId}"
limit="20"
data="saleTrackings"
order="itemFk DESC"
auto-load="true">
</vn-crud-model>
<vn-data-viewer model="modelSaleTracking">
<vn-card class="vn-w-lg">
<vn-table model="modelSaleTracking">
<vn-thead>
<vn-tr>
<vn-th field="quantity" number>Quantity</vn-th>
<vn-th field="originalQuantity" number>Original</vn-th>
<vn-th field="workerFk">Worker</vn-th>
<vn-th field="state" shrink>State</vn-th>
<vn-th field="created" expand>Created</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="sale in saleTrackings">
<vn-td number>{{::sale.quantity}}</vn-td>
<vn-td number>{{::sale.originalQuantity}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="workerDescriptor.show($event, sale.workerFk)">
{{::sale.userNickname | dashIfEmpty}}
</span>
</vn-td>
<vn-td shrink>{{::sale.state}}</vn-td>
<vn-td expand>{{::sale.created | date: 'dd/MM/yyyy HH:mm'}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-data-viewer>
<vn-item-descriptor-popover
vn-id="item-descriptor"
warehouse-fk="$ctrl.ticket.warehouseFk">
</vn-item-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="worker-descriptor">
</vn-worker-descriptor-popover>
</vn-popup>
<vn-popup vn-id="itemShelvingSale">
<vn-crud-model
vn-id="modelSaleTracking"
url="ItemShelvingSales/filter"
link="{saleFk: $ctrl.saleId}"
limit="20"
data="$ctrl.itemShelvingSales"
auto-load="true">
</vn-crud-model>
<vn-data-viewer model="modelSaleTracking">
<vn-card class="vn-w-lg">
<vn-table model="modelSaleTracking">
<vn-thead>
<vn-tr>
<vn-th field="quantity" number>Quantity</vn-th>
<vn-th field="workerFk">Worker</vn-th>
<vn-th field="shelving" shrink>Shelving</vn-th>
<vn-th field="parking" shrink>Parking</vn-th>
<vn-th field="created" expand>Created</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="itemShelvingSale in $ctrl.itemShelvingSales">
<vn-td number>{{::itemShelvingSale.quantity}}</vn-td>
<vn-td expand>
<span
class="link"
ng-click="workerDescriptor.show($event, itemShelvingSale.userFk)">
{{::itemShelvingSale.name | dashIfEmpty}}
</span>
</vn-td>
<vn-td shrink>{{::itemShelvingSale.shelvingFk}}</vn-td>
<vn-td shrink>{{::itemShelvingSale.code}}</vn-td>
<vn-td expand>{{::itemShelvingSale.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="worker-descriptor">
</vn-worker-descriptor-popover>
</vn-popup>

View File

@ -1,12 +1,100 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section'; import Section from 'salix/components/section';
import './style.scss';
class Controller extends Section {} class Controller extends Section {
constructor($element, $) {
super($element, $);
this.filter = {
include: [
{
relation: 'item'
}, {
relation: 'saleTracking',
scope: {
fields: ['isChecked']
}
}
]
};
}
get sales() {
return this._sales;
}
set sales(value) {
this._sales = value;
if (value) {
const query = `Sales/${this.$params.id}/salePreparingList`;
this.$http.get(query)
.then(res => {
this.salePreparingList = res.data;
for (const salePreparing of this.salePreparingList) {
for (const sale of this.sales) {
if (salePreparing.saleFk == sale.id)
sale.preparingList = salePreparing;
}
}
});
}
}
showItemDescriptor(event, sale) {
this.quicklinks = {
btnThree: {
icon: 'icon-transaction',
state: `item.card.diary({
id: ${sale.itemFk},
warehouseFk: ${this.ticket.warehouseFk},
lineFk: ${sale.id}
})`,
tooltip: 'Item diary'
}
};
this.$.itemDescriptor.show(event.target, sale.itemFk);
}
chipHasSaleGroupDetail(hasSaleGroupDetail) {
if (hasSaleGroupDetail) return 'pink';
else return 'message';
}
chipIsPreviousSelected(isPreviousSelected) {
if (isPreviousSelected) return 'notice';
else return 'message';
}
chipIsPrevious(isPrevious) {
if (isPrevious) return 'dark-notice';
else return 'message';
}
chipIsPrepared(isPrepared) {
if (isPrepared) return 'warning';
else return 'message';
}
chipIsControled(isControled) {
if (isControled) return 'yellow';
else return 'message';
}
showSaleTracking(sale) {
this.saleId = sale.id;
this.$.saleTracking.show();
}
showItemShelvingSale(sale) {
this.saleId = sale.id;
this.$.itemShelvingSale.show();
}
}
ngModule.vnComponent('vnTicketSaleTracking', { ngModule.vnComponent('vnTicketSaleTracking', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,
bindings: { bindings: {
ticket: '<', ticket: '<'
}, }
}); });

View File

@ -0,0 +1,6 @@
ItemShelvings sale: Carros línea
has saleGroupDetail: tiene detalle grupo lineas
is previousSelected: es previa seleccionada
is previous: es previa
is prepared: esta preparado
is controled: esta controlado

View File

@ -0,0 +1,7 @@
@import "variables";
.chip {
display: inline-block;
min-width: 15px;
min-height: 25px;
}