#7323 worker/filter #2978
|
@ -98,22 +98,8 @@ BEGIN
|
|||
SELECT employeeFk INTO vUserFk FROM orderConfig;
|
||||
END IF;
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
CALL order_checkEditable(vSelf);
|
||||
|
||||
CALL orderRow_updateOverstocking(vSelf);
|
||||
|
||||
-- Check order is not empty
|
||||
SELECT COUNT(*) > 0 INTO vHasRows
|
||||
FROM orderRow
|
||||
WHERE orderFk = vSelf
|
||||
AND amount > 0;
|
||||
|
||||
IF NOT vHasRows THEN
|
||||
CALL util.throw('ORDER_EMPTY');
|
||||
END IF;
|
||||
|
||||
-- Check if any product has a quantity of 0
|
||||
SELECT EXISTS (
|
||||
SELECT id
|
||||
|
@ -126,6 +112,20 @@ BEGIN
|
|||
CALL util.throw('Remove lines with quantity = 0 before confirming');
|
||||
END IF;
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
CALL order_checkEditable(vSelf);
|
||||
|
||||
-- Check order is not empty
|
||||
SELECT COUNT(*) > 0 INTO vHasRows
|
||||
FROM orderRow
|
||||
WHERE orderFk = vSelf
|
||||
AND amount > 0;
|
||||
|
||||
IF NOT vHasRows THEN
|
||||
CALL util.throw('ORDER_EMPTY');
|
||||
END IF;
|
||||
|
||||
-- Crea los tickets del pedido
|
||||
OPEN vDates;
|
||||
lDates: LOOP
|
||||
|
|
|
@ -23,6 +23,13 @@ BEGIN
|
|||
DELETE FROM messageInbox WHERE sendDate < v2Months;
|
||||
DELETE FROM messageInbox WHERE sendDate < v2Months;
|
||||
DELETE FROM workerTimeControl WHERE timed < v4Years;
|
||||
DELETE FROM itemShelvingSale
|
||||
WHERE itemShelvingFk IN (
|
||||
SELECT id
|
||||
FROM itemShelving
|
||||
WHERE created < util.VN_CURDATE()
|
||||
AND visible = 0
|
||||
);
|
||||
DELETE FROM itemShelving WHERE created < util.VN_CURDATE() AND visible = 0;
|
||||
DELETE FROM ticketDown WHERE created < util.yesterday();
|
||||
DELETE IGNORE FROM expedition WHERE created < v26Months;
|
||||
|
|
|
@ -45,6 +45,12 @@ BEGIN
|
|||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||
-- Si hay colecciones sin terminar, sale del proceso
|
||||
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
CALL collection_get(vUserFk);
|
||||
|
||||
SELECT (pc.maxNotReadyCollections - COUNT(*)) <= 0, pc.maxNotAssignedCollectionLifeTime
|
||||
|
@ -118,9 +124,19 @@ BEGIN
|
|||
IF vCollectionFk IS NULL THEN
|
||||
CALL collection_new(vUserFk, vCollectionFk);
|
||||
|
||||
UPDATE `collection`
|
||||
SET workerFk = vUserFk
|
||||
WHERE id = vCollectionFk;
|
||||
START TRANSACTION;
|
||||
|
||||
SELECT workerFk INTO vCollectionWorker
|
||||
FROM `collection`
|
||||
WHERE id = vCollectionFk FOR UPDATE;
|
||||
|
||||
IF vCollectionWorker IS NULL THEN
|
||||
UPDATE `collection`
|
||||
SET workerFk = vUserFk
|
||||
WHERE id = vCollectionFk;
|
||||
END IF;
|
||||
|
||||
COMMIT;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -40,7 +40,7 @@ BEGIN
|
|||
isTooLittle BOOL DEFAULT FALSE,
|
||||
isVip BOOL DEFAULT FALSE,
|
||||
PRIMARY KEY (ticketFk, saleFk)
|
||||
) ENGINE = MEMORY;
|
||||
); -- No memory
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk,
|
||||
saleFk,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE vn.itemShelving DROP FOREIGN KEY itemShelving_fk2;
|
||||
ALTER TABLE vn.itemShelving ADD CONSTRAINT itemShelving_fk2
|
||||
FOREIGN KEY (shelvingFk) REFERENCES vn.shelving(code) ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -66,15 +66,15 @@ export default class App {
|
|||
]}
|
||||
};
|
||||
|
||||
const hasId = !isNaN(parseInt(route.split('/')[1]));
|
||||
|
||||
if (this.logger.$params.q) {
|
||||
let tableValue = this.logger.$params.q;
|
||||
const q = JSON.parse(tableValue);
|
||||
if (typeof q === 'number')
|
||||
tableValue = JSON.stringify({id: tableValue});
|
||||
newRoute = newRoute.concat(`?table=${tableValue}`);
|
||||
}
|
||||
|
||||
if (this.logger.$params.id && newRoute.indexOf(this.logger.$params.id) < 0)
|
||||
} else if (!hasId && this.logger.$params.id && newRoute.indexOf(this.logger.$params.id) < 0)
|
||||
newRoute = newRoute.concat(`${this.logger.$params.id}`);
|
||||
|
||||
return this.logger.$http.get('Urls/findOne', {filter})
|
||||
|
|
|
@ -34,6 +34,11 @@ module.exports = Self => {
|
|||
try {
|
||||
const promises = [];
|
||||
for (let itemShelvingId of itemShelvingIds) {
|
||||
const itemShelvingSaleToDelete = models.ItemShelvingSale.destroyAll({
|
||||
itemShelvingFk: itemShelvingId
|
||||
}, myOptions);
|
||||
promises.push(itemShelvingSaleToDelete);
|
||||
|
||||
const itemShelvingToDelete = models.ItemShelving.destroyById(itemShelvingId, myOptions);
|
||||
promises.push(itemShelvingToDelete);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ describe('ItemShelving deleteItemShelvings()', () => {
|
|||
const itemShelvingIds = [1, 2];
|
||||
const result = await models.ItemShelving.deleteItemShelvings(itemShelvingIds, options);
|
||||
|
||||
expect(result.length).toEqual(2);
|
||||
expect(result.length).toEqual(4);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
export * from './module';
|
||||
|
||||
import './main';
|
||||
import './index/';
|
||||
import './index/tickets';
|
||||
import './index/clients';
|
||||
import './index/orders';
|
||||
import './index/search-panel';
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="SalesMonitors/clientsFilter"
|
||||
limit="6"
|
||||
filter="$ctrl.filter"
|
||||
order="dated DESC, hour DESC"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-horizontal class="header">
|
||||
<vn-one translate>
|
||||
Clients on website
|
||||
</vn-one>
|
||||
<vn-none>
|
||||
<vn-icon class="arrow"
|
||||
icon="keyboard_arrow_up"
|
||||
vn-tooltip="Minimize/Maximize"
|
||||
ng-click="$ctrl.main.toggle()">
|
||||
</vn-icon>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-card vn-id="card">
|
||||
<smart-table
|
||||
model="model"
|
||||
options="$ctrl.smartTableOptions"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)"
|
||||
disabled-table-filter="true"
|
||||
disabled-table-order="true"
|
||||
class="scrollable sm">
|
||||
<slot-actions>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
class="vn-pa-xs"
|
||||
label="From"
|
||||
ng-model="$ctrl.dateFrom"
|
||||
on-change="$ctrl.addFilterDate()">
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
class="vn-pa-xs"
|
||||
label="To"
|
||||
ng-model="$ctrl.dateTo"
|
||||
on-change="$ctrl.addFilterDate()">
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
</slot-actions>
|
||||
<slot-table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th field="dated">
|
||||
<span translate>Date</span>
|
||||
</th>
|
||||
<th field="hour">
|
||||
<span translate>Hour</span>
|
||||
</th>
|
||||
<th field="salesPersonFk" class="expendable">
|
||||
<span translate>Salesperson</span>
|
||||
</th>
|
||||
<th field="clientFk">
|
||||
<span translate>Client</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="visit in model.data track by visit.id">
|
||||
<td shrink-date>
|
||||
<span class="chip">
|
||||
{{::visit.dated | date:'dd/MM/yy'}}
|
||||
</span>
|
||||
</td>
|
||||
<td shrink-date>
|
||||
<span class="chip">
|
||||
{{::visit.hour | date: 'HH:mm'}}
|
||||
</span>
|
||||
</td>
|
||||
<td class="shrink expendable">
|
||||
<span
|
||||
title="{{::visit.salesPerson}}"
|
||||
vn-click-stop="workerDescriptor.show($event, visit.salesPersonFk)"
|
||||
class="link">
|
||||
{{::visit.salesPerson | dashIfEmpty}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
title="{{::visit.clientName}}"
|
||||
vn-click-stop="clientDescriptor.show($event, visit.clientFk)"
|
||||
class="link">
|
||||
{{::visit.clientName}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</slot-table>
|
||||
<slot-pagination>
|
||||
<vn-pagination
|
||||
model="model"
|
||||
class="vn-pt-xs"
|
||||
scroll-selector="vn-monitor-sales-clients smart-table"
|
||||
scroll-offset="100">
|
||||
</vn-pagination>
|
||||
</slot-pagination>
|
||||
</smart-table>
|
||||
</vn-card>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-client-descriptor-popover
|
||||
vn-id="clientDescriptor">
|
||||
</vn-client-descriptor-popover>
|
|
@ -1,96 +0,0 @@
|
|||
import ngModule from '../../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
export default class Controller extends Section {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
|
||||
const date = Date.vnNew();
|
||||
this.dateFrom = date;
|
||||
this.dateTo = date;
|
||||
this.filter = {
|
||||
where: {
|
||||
'v.stamp': {
|
||||
between: this.dateRange()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.smartTableOptions = {
|
||||
activeButtons: {
|
||||
search: true
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'clientFk',
|
||||
autocomplete: {
|
||||
url: 'Clients',
|
||||
showField: 'name',
|
||||
valueField: 'id'
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'salesPersonFk',
|
||||
autocomplete: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
where: `{role: 'salesPerson'}`,
|
||||
searchFunction: '{firstName: $search}',
|
||||
showField: 'nickname',
|
||||
valueField: 'id',
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'dated',
|
||||
searchable: false
|
||||
},
|
||||
{
|
||||
field: 'hour',
|
||||
searchable: false
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'clientFk':
|
||||
return {[`c.id`]: value};
|
||||
case 'salesPersonFk':
|
||||
return {[`c.${param}`]: value};
|
||||
}
|
||||
}
|
||||
|
||||
dateRange() {
|
||||
let from = this.dateFrom;
|
||||
let to = this.dateTo;
|
||||
if (!from)
|
||||
from = Date.vnNew();
|
||||
if (!to)
|
||||
to = Date.vnNew();
|
||||
const minHour = new Date(from);
|
||||
minHour.setHours(0, 0, 0, 0);
|
||||
const maxHour = new Date(to);
|
||||
maxHour.setHours(23, 59, 59, 59);
|
||||
|
||||
return [minHour, maxHour];
|
||||
}
|
||||
|
||||
addFilterDate() {
|
||||
this.$.model.filter = {
|
||||
where: {
|
||||
'v.stamp': {
|
||||
between: this.dateRange()
|
||||
}
|
||||
}
|
||||
};
|
||||
this.$.model.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnMonitorSalesClients', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
require: {
|
||||
main: '^vnMonitorIndex'
|
||||
}
|
||||
});
|
|
@ -1,5 +0,0 @@
|
|||
<vn-horizontal ng-class="{'hidden': $ctrl.isTopPanelHidden}">
|
||||
<vn-monitor-sales-clients class="vn-mb-sm"></vn-monitor-sales-clients>
|
||||
<vn-monitor-sales-orders></vn-monitor-sales-orders>
|
||||
</vn-horizontal>
|
||||
<vn-monitor-sales-tickets></vn-monitor-sales-tickets>
|
|
@ -1,34 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
import './style.scss';
|
||||
|
||||
export default class Controller extends Section {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
|
||||
const isTopPanelHidden = localStorage.getItem('ticketTopPanelHidden');
|
||||
if (isTopPanelHidden === 'true')
|
||||
this.isTopPanelHidden = true;
|
||||
}
|
||||
|
||||
toggle() {
|
||||
const monitor = this.element.querySelector('vn-horizontal');
|
||||
const isHidden = monitor.classList.contains('hidden');
|
||||
|
||||
if (!isHidden) {
|
||||
monitor.classList.add('hidden');
|
||||
localStorage.setItem('ticketTopPanelHidden', true);
|
||||
} else {
|
||||
monitor.classList.remove('hidden');
|
||||
localStorage.setItem('ticketTopPanelHidden', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnMonitorIndex', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
require: {
|
||||
main: '^vnMonitorIndex'
|
||||
}
|
||||
});
|
|
@ -1,38 +0,0 @@
|
|||
import './index.js';
|
||||
describe('Component vnMonitorIndex', () => {
|
||||
let controller;
|
||||
let $element;
|
||||
|
||||
beforeEach(ngModule('monitor'));
|
||||
|
||||
beforeEach(inject(($compile, $rootScope) => {
|
||||
$element = $compile('<vn-monitor-index></vn-monitor-index>')($rootScope);
|
||||
controller = $element.controller('vnMonitorIndex');
|
||||
}));
|
||||
|
||||
describe('toggle()', () => {
|
||||
it('should add the hidden class to the horizontal contaning the panel to hide', () => {
|
||||
controller.toggle();
|
||||
|
||||
const targetElement = $element[0].querySelector('vn-horizontal');
|
||||
const firstClass = targetElement.classList[0];
|
||||
|
||||
const isTopPanelHidden = localStorage.getItem('ticketTopPanelHidden');
|
||||
|
||||
expect(firstClass).toEqual('hidden');
|
||||
expect(isTopPanelHidden).toEqual('true');
|
||||
});
|
||||
|
||||
it('should remove the hidden class to the horizontal contaning the panel to hide', () => {
|
||||
const targetElement = $element[0].querySelector('vn-horizontal');
|
||||
targetElement.classList.add('hidden');
|
||||
controller.toggle();
|
||||
const firstClass = targetElement.classList[0];
|
||||
|
||||
const isTopPanelHidden = localStorage.getItem('ticketTopPanelHidden');
|
||||
|
||||
expect(firstClass).toBeUndefined();
|
||||
expect(isTopPanelHidden).toEqual('false');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,16 +0,0 @@
|
|||
Tickets monitor: Monitor de tickets
|
||||
Clients on website: Clientes activos en la web
|
||||
Recent order actions: Acciones recientes en pedidos
|
||||
Search tickets: Buscar tickets
|
||||
Delete selected elements: Eliminar los elementos seleccionados
|
||||
All the selected elements will be deleted. Are you sure you want to continue?: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar?
|
||||
Component lack: Faltan componentes
|
||||
Ticket too little: Ticket demasiado pequeño
|
||||
Minimize/Maximize: Minimizar/Maximizar
|
||||
Problems: Problemas
|
||||
Theoretical: Teórica
|
||||
Practical: Práctica
|
||||
Preparation: Preparación
|
||||
Auto-refresh: Auto-refresco
|
||||
Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos
|
||||
Is fragile: Es frágil
|
|
@ -1,141 +0,0 @@
|
|||
<vn-crud-model auto-load="true"
|
||||
vn-id="model"
|
||||
url="SalesMonitors/ordersFilter"
|
||||
limit="6"
|
||||
order="date_make DESC">
|
||||
</vn-crud-model>
|
||||
<vn-horizontal class="header">
|
||||
<vn-one translate>
|
||||
Recent order actions
|
||||
</vn-one>
|
||||
<vn-none>
|
||||
<vn-icon
|
||||
icon="delete"
|
||||
vn-tooltip="Delete"
|
||||
ng-if="$ctrl.totalChecked > 0"
|
||||
ng-click="delete.show()">
|
||||
</vn-icon>
|
||||
<vn-icon class="arrow"
|
||||
icon="keyboard_arrow_up"
|
||||
vn-tooltip="Minimize/Maximize"
|
||||
ng-click="$ctrl.main.toggle()">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
icon="refresh"
|
||||
vn-tooltip="Refresh"
|
||||
ng-click="model.refresh()">
|
||||
</vn-icon>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-card>
|
||||
<vn-table model="model" class="scrollable">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th shrink>
|
||||
<vn-multi-check
|
||||
model="model">
|
||||
</vn-multi-check>
|
||||
</vn-th>
|
||||
<vn-th field="date_send" shrink-datetime>Date</vn-th>
|
||||
<vn-th field="clientFk">Client</vn-th>
|
||||
<vn-th field="salesPersonFk" shrink>SalesPerson</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<a ng-repeat="order in model.data track by order.id"
|
||||
class="clickable vn-tbody"
|
||||
ui-sref="order.card.summary({id: {{::order.id}}})" target="_blank">
|
||||
<vn-tr>
|
||||
<vn-td>
|
||||
<vn-check
|
||||
ng-model="order.checked"
|
||||
vn-click-stop>
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span class="chip {{::$ctrl.chipColor(order.date_send)}}">
|
||||
{{::order.date_send | date: 'dd/MM/yyyy'}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span
|
||||
title="{{::order.clientName}}"
|
||||
vn-click-stop="clientDescriptor.show($event, order.clientFk)"
|
||||
class="link">
|
||||
{{::order.clientName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span
|
||||
title="{{::order.salesPerson}}"
|
||||
vn-click-stop="workerDescriptor.show($event, order.salesPersonFk)"
|
||||
class="link">
|
||||
{{::order.salesPerson | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
<vn-tr>
|
||||
<vn-td></vn-td>
|
||||
<vn-td>
|
||||
<span>
|
||||
{{::order.date_make | date: 'dd/MM/yyyy HH:mm'}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span title="{{::order.agencyName}}">
|
||||
{{::order.agencyName | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
{{::order.import | currency: 'EUR':2}}
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</a>
|
||||
</vn-table>
|
||||
<vn-pagination
|
||||
model="model"
|
||||
class="vn-pt-xs"
|
||||
scroll-selector="vn-monitor-sales-orders vn-table"
|
||||
scroll-offset="100">
|
||||
</vn-pagination>
|
||||
</vn-card>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-client-descriptor-popover
|
||||
vn-id="clientDescriptor">
|
||||
</vn-client-descriptor-popover>
|
||||
<vn-contextmenu vn-id="contextmenu" targets="['vn-monitor-sales-orders vn-table']" model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
<slot-menu>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.filterBySelection()">
|
||||
Filter by selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.excludeSelection()">
|
||||
Exclude selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.removeFilter()">
|
||||
Remove filter
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-click="contextmenu.removeAllFilters()">
|
||||
Remove all filters
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isActionAllowed()"
|
||||
ng-click="contextmenu.copyValue()">
|
||||
Copy value
|
||||
</vn-item>
|
||||
</slot-menu>
|
||||
</vn-contextmenu>
|
||||
<vn-confirm
|
||||
vn-id="delete"
|
||||
on-accept="$ctrl.onDelete()"
|
||||
question="All the selected elements will be deleted. Are you sure you want to continue?"
|
||||
message="Delete selected elements">
|
||||
</vn-confirm>
|
|
@ -1,74 +0,0 @@
|
|||
import ngModule from '../../module';
|
||||
import Section from 'salix/components/section';
|
||||
import './style.scss';
|
||||
|
||||
export default class Controller extends Section {
|
||||
get checked() {
|
||||
const rows = this.$.model.data || [];
|
||||
const checkedRows = [];
|
||||
for (let row of rows) {
|
||||
if (row.checked)
|
||||
checkedRows.push(row.id);
|
||||
}
|
||||
|
||||
return checkedRows;
|
||||
}
|
||||
|
||||
get totalChecked() {
|
||||
return this.checked.length;
|
||||
}
|
||||
|
||||
onDelete() {
|
||||
const params = {deletes: this.checked};
|
||||
const query = `SalesMonitors/deleteOrders`;
|
||||
this.$http.post(query, params).then(
|
||||
() => this.$.model.refresh());
|
||||
}
|
||||
|
||||
chipColor(date) {
|
||||
const today = Date.vnNew();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
const orderLanded = new Date(date);
|
||||
orderLanded.setHours(0, 0, 0, 0);
|
||||
|
||||
const difference = today - orderLanded;
|
||||
|
||||
if (difference == 0)
|
||||
return 'warning';
|
||||
if (difference < 0)
|
||||
return 'success';
|
||||
if (difference > 0)
|
||||
return 'alert';
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'date_send':
|
||||
return {[`o.date_send`]: {
|
||||
between: this.dateRange(value)}
|
||||
};
|
||||
case 'clientFk':
|
||||
return {[`c.id`]: value};
|
||||
case 'salesPersonFk':
|
||||
return {[`c.${param}`]: value};
|
||||
}
|
||||
}
|
||||
|
||||
dateRange(value) {
|
||||
const minHour = new Date(value);
|
||||
minHour.setHours(0, 0, 0, 0);
|
||||
const maxHour = new Date(value);
|
||||
maxHour.setHours(23, 59, 59, 59);
|
||||
|
||||
return [minHour, maxHour];
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnMonitorSalesOrders', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
require: {
|
||||
main: '^vnMonitorIndex'
|
||||
}
|
||||
});
|
|
@ -1,50 +0,0 @@
|
|||
import './index.js';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('Component vnMonitorSalesOrders', () => {
|
||||
let controller;
|
||||
let $httpBackend;
|
||||
|
||||
beforeEach(ngModule('monitor'));
|
||||
|
||||
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
const $element = angular.element('<vn-monitor-sales-orders></vn-monitor-sales-orders>');
|
||||
controller = $componentController('vnMonitorSalesOrders', {$element});
|
||||
controller.$.model = crudModel;
|
||||
controller.$.model.data = [
|
||||
{id: 1, name: 'My item 1'},
|
||||
{id: 2, name: 'My item 2'},
|
||||
{id: 3, name: 'My item 3'}
|
||||
];
|
||||
}));
|
||||
|
||||
describe('checked() getter', () => {
|
||||
it('should return a the selected rows', () => {
|
||||
const modelData = controller.$.model.data;
|
||||
modelData[0].checked = true;
|
||||
modelData[1].checked = true;
|
||||
|
||||
const result = controller.checked;
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([1, 2]));
|
||||
});
|
||||
});
|
||||
|
||||
describe('onDelete()', () => {
|
||||
it('should make a query and then call to the model refresh() method', () => {
|
||||
jest.spyOn(controller.$.model, 'refresh');
|
||||
|
||||
const modelData = controller.$.model.data;
|
||||
modelData[0].checked = true;
|
||||
modelData[1].checked = true;
|
||||
|
||||
const expectedParams = {deletes: [1, 2]};
|
||||
$httpBackend.expect('POST', 'SalesMonitors/deleteOrders', expectedParams).respond(200);
|
||||
controller.onDelete();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.model.refresh).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
@import "variables";
|
||||
|
||||
vn-monitor-sales-orders {
|
||||
vn-table.scrollable {
|
||||
max-height: 350px;
|
||||
overflow-x: hidden
|
||||
}
|
||||
|
||||
vn-table a.vn-tbody {
|
||||
& > vn-tr:nth-child(2) {
|
||||
color: gray;
|
||||
|
||||
& > vn-td {
|
||||
border-bottom: $border;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
<div class="search-panel">
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
url="Warehouses"
|
||||
data="warehouses">
|
||||
</vn-crud-model>
|
||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal class="vn-px-lg vn-pt-lg">
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="General search"
|
||||
ng-model="filter.search"
|
||||
info="Search ticket by id or alias"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-px-lg">
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Client id"
|
||||
ng-model="filter.clientFk">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Order id"
|
||||
ng-model="filter.orderFk">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-px-lg">
|
||||
<vn-input-number
|
||||
vn-one
|
||||
min="0"
|
||||
step="1"
|
||||
label="Days onward"
|
||||
ng-model="filter.scopeDays"
|
||||
on-change="$ctrl.scopeDays = value"
|
||||
display-controls="true">
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-px-lg">
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Nickname"
|
||||
ng-model="filter.nickname">
|
||||
</vn-textfield>
|
||||
<vn-worker-autocomplete
|
||||
vn-one
|
||||
ng-model="filter.salesPersonFk"
|
||||
departments="['VT']"
|
||||
label="Sales person">
|
||||
</vn-worker-autocomplete>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Invoice"
|
||||
ng-model="filter.refFk">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-px-lg">
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Agency"
|
||||
ng-model="filter.agencyModeFk"
|
||||
url="AgencyModes/isActive">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="State"
|
||||
ng-model="filter.stateFk"
|
||||
url="States">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
data="$ctrl.groupedStates"
|
||||
label="Grouped States"
|
||||
value-field="id"
|
||||
show-field="name"
|
||||
ng-model="filter.alertLevel">
|
||||
<tpl-item>
|
||||
{{name}}
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-px-lg">
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="filter.warehouseFk"
|
||||
data="warehouses">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Province"
|
||||
ng-model="filter.provinceFk"
|
||||
url="Provinces">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-px-lg">
|
||||
<vn-check
|
||||
vn-one
|
||||
label="My team"
|
||||
ng-model="filter.myTeam"
|
||||
triple-state="true">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
vn-one
|
||||
label="With problems"
|
||||
ng-model="filter.problems"
|
||||
triple-state="true">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
vn-one
|
||||
label="Pending"
|
||||
ng-model="filter.pending"
|
||||
triple-state="true">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-px-lg vn-pb-lg vn-mt-lg">
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
</form>
|
||||
</div>
|
|
@ -1,59 +0,0 @@
|
|||
import ngModule from '../../module';
|
||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
||||
|
||||
class Controller extends SearchPanel {
|
||||
constructor($, $element) {
|
||||
super($, $element);
|
||||
this.filter = this.$.filter;
|
||||
|
||||
this.getGroupedStates();
|
||||
}
|
||||
|
||||
getGroupedStates() {
|
||||
let groupedStates = [];
|
||||
this.$http.get('AlertLevels').then(res => {
|
||||
for (let state of res.data) {
|
||||
groupedStates.push({
|
||||
id: state.id,
|
||||
code: state.code,
|
||||
name: this.$t(state.code)
|
||||
});
|
||||
}
|
||||
this.groupedStates = groupedStates;
|
||||
});
|
||||
}
|
||||
|
||||
get from() {
|
||||
return this._from;
|
||||
}
|
||||
|
||||
set from(value) {
|
||||
this._from = value;
|
||||
this.filter.scopeDays = null;
|
||||
}
|
||||
|
||||
get to() {
|
||||
return this._to;
|
||||
}
|
||||
|
||||
set to(value) {
|
||||
this._to = value;
|
||||
this.filter.scopeDays = null;
|
||||
}
|
||||
|
||||
get scopeDays() {
|
||||
return this._scopeDays;
|
||||
}
|
||||
|
||||
set scopeDays(value) {
|
||||
this._scopeDays = value;
|
||||
|
||||
this.filter.from = null;
|
||||
this.filter.to = null;
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnMonitorSalesSearchPanel', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -1,71 +0,0 @@
|
|||
import './index';
|
||||
|
||||
describe('Monitor Component vnMonitorSalesSearchPanel', () => {
|
||||
let $httpBackend;
|
||||
let controller;
|
||||
|
||||
beforeEach(ngModule('monitor'));
|
||||
|
||||
beforeEach(inject(($componentController, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
controller = $componentController('vnMonitorSalesSearchPanel', {$element: null});
|
||||
controller.$t = () => {};
|
||||
controller.filter = {};
|
||||
}));
|
||||
|
||||
describe('getGroupedStates()', () => {
|
||||
it('should set an array of groupedStates with the adition of a name translation', () => {
|
||||
jest.spyOn(controller, '$t').mockReturnValue('miCodigo');
|
||||
const data = [
|
||||
{
|
||||
id: 9999,
|
||||
code: 'myCode'
|
||||
}
|
||||
];
|
||||
$httpBackend.whenGET('AlertLevels').respond(data);
|
||||
controller.getGroupedStates();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.groupedStates).toEqual([{
|
||||
id: 9999,
|
||||
code: 'myCode',
|
||||
name: 'miCodigo'
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('from() setter', () => {
|
||||
it('should clear the scope days when setting the from property', () => {
|
||||
controller.filter.scopeDays = 1;
|
||||
|
||||
controller.from = Date.vnNew();
|
||||
|
||||
expect(controller.filter.scopeDays).toBeNull();
|
||||
expect(controller.from).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('to() setter', () => {
|
||||
it('should clear the scope days when setting the to property', () => {
|
||||
controller.filter.scopeDays = 1;
|
||||
|
||||
controller.to = Date.vnNew();
|
||||
|
||||
expect(controller.filter.scopeDays).toBeNull();
|
||||
expect(controller.to).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('scopeDays() setter', () => {
|
||||
it('should clear the date range when setting the scopeDays property', () => {
|
||||
controller.filter.from = Date.vnNew();
|
||||
controller.filter.to = Date.vnNew();
|
||||
|
||||
controller.scopeDays = 1;
|
||||
|
||||
expect(controller.filter.from).toBeNull();
|
||||
expect(controller.filter.to).toBeNull();
|
||||
expect(controller.scopeDays).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,85 +0,0 @@
|
|||
@import "variables";
|
||||
@import "effects";
|
||||
|
||||
vn-monitor-index {
|
||||
.header {
|
||||
padding: 12px 0 5px 0;
|
||||
color: gray;
|
||||
font-size: 1.2rem;
|
||||
border-bottom: $border;
|
||||
margin-bottom: 10px;
|
||||
|
||||
& > vn-none > vn-icon {
|
||||
@extend %clickable-light;
|
||||
color: $color-button;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
vn-none > .arrow {
|
||||
transition: transform 200ms;
|
||||
}
|
||||
}
|
||||
|
||||
vn-monitor-sales-clients {
|
||||
vn-card {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding-right: 15px;
|
||||
|
||||
& > vn-none > .arrow {
|
||||
display: none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vn-table.scrollable {
|
||||
height: 300px
|
||||
}
|
||||
|
||||
vn-horizontal {
|
||||
flex-wrap: wrap
|
||||
}
|
||||
|
||||
.hidden {
|
||||
vn-card {
|
||||
display: none
|
||||
}
|
||||
|
||||
.header > vn-none > .arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:1150px) {
|
||||
vn-monitor-index {
|
||||
& > vn-horizontal {
|
||||
flex-direction: column;
|
||||
|
||||
vn-monitor-sales-clients,
|
||||
vn-monitor-sales-orders {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
vn-monitor-sales-clients {
|
||||
margin-bottom: 15px
|
||||
}
|
||||
}
|
||||
|
||||
vn-monitor-sales-clients {
|
||||
vn-card {
|
||||
margin-right: 0
|
||||
}
|
||||
|
||||
.header {
|
||||
padding-right: 0;
|
||||
|
||||
& > vn-none > .arrow {
|
||||
display: inline-block
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="SalesMonitors/salesFilter"
|
||||
auto-load="false"
|
||||
limit="20">
|
||||
</vn-crud-model>
|
||||
<vn-portal slot="topbar">
|
||||
<vn-searchbar
|
||||
vn-focus
|
||||
panel="vn-monitor-sales-search-panel"
|
||||
placeholder="Search tickets"
|
||||
info="Search ticket by id or alias"
|
||||
model="model"
|
||||
fetch-params="$ctrl.fetchParams($params)"
|
||||
suggested-filter="$ctrl.filterParams"
|
||||
auto-state="false">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<vn-horizontal class="header">
|
||||
<vn-one translate>
|
||||
Tickets monitor
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-card>
|
||||
<smart-table
|
||||
model="model"
|
||||
view-config-id="ticketsMonitor"
|
||||
options="$ctrl.smartTableOptions"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
<slot-actions>
|
||||
<vn-check
|
||||
label="Auto-refresh"
|
||||
vn-tooltip="Toggle auto-refresh every 2 minutes"
|
||||
on-change="$ctrl.autoRefresh(value)">
|
||||
</vn-check>
|
||||
</slot-actions>
|
||||
<slot-table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th field="totalProblems" menu-enabled="false">
|
||||
<span translate>Problems</span>
|
||||
</th>
|
||||
<th field="id">
|
||||
<span translate>Identifier</span>
|
||||
</th>
|
||||
<th field="nickname">
|
||||
<span translate>Client</span>
|
||||
</th>
|
||||
<th field="salesPersonFk">
|
||||
<span translate>Salesperson</span>
|
||||
</th>
|
||||
<th field="shippedDate" shrink-date filter-enabled="false">
|
||||
<span translate>Date</span>
|
||||
</th>
|
||||
<th field="theoreticalHour" filter-enabled="false">
|
||||
<span translate>Theoretical</span>
|
||||
</th>
|
||||
<th field="practicalHour" filter-enabled="false">
|
||||
<span translate>Practical</span>
|
||||
</th>
|
||||
<th field="preparationHour" filter-enabled="false">
|
||||
<span translate>Preparation</span>
|
||||
</th>
|
||||
<th field="provinceFk">
|
||||
<span translate>Province</span>
|
||||
</th>
|
||||
<th field="stateFk">
|
||||
<span translate>State</span>
|
||||
</th>
|
||||
<th field="isFragile" number>
|
||||
<span translate>Fragile</span>
|
||||
</th>
|
||||
<th field="zoneFk">
|
||||
<span translate>Zone</span>
|
||||
</th>
|
||||
<th field="totalWithVat" shrink>
|
||||
<span translate>Total</span>
|
||||
</th>
|
||||
<th shrink></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="ticket in model.data track by ticket.id"
|
||||
vn-anchor="{
|
||||
state: 'ticket.card.summary',
|
||||
params: {id: ticket.id},
|
||||
target: '_blank'
|
||||
}">
|
||||
<td>
|
||||
<vn-icon
|
||||
ng-show="ticket.isTaxDataChecked === 0"
|
||||
translate-attr="{title: 'No verified data'}"
|
||||
class="bright"
|
||||
icon="icon-no036">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-show="ticket.hasTicketRequest"
|
||||
translate-attr="{title: 'Purchase request'}"
|
||||
class="bright"
|
||||
icon="icon-buyrequest">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-show="ticket.itemShortage"
|
||||
translate-attr="{title: 'Not visible'}"
|
||||
class="bright"
|
||||
icon="icon-unavailable">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-show="ticket.isFreezed"
|
||||
translate-attr="{title: 'Client frozen'}"
|
||||
class="bright"
|
||||
icon="icon-frozen">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-show="ticket.risk"
|
||||
ng-class="{'highRisk': ticket.hasHighRisk}"
|
||||
title="{{$ctrl.$t('Risk')}}: {{ticket.risk}}"
|
||||
class="bright"
|
||||
icon="icon-risk">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-show="ticket.hasComponentLack"
|
||||
translate-attr="{title: 'Component lack'}"
|
||||
class="bright"
|
||||
icon="icon-components">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-show="ticket.isTooLittle"
|
||||
translate-attr="{title: 'Ticket too little'}"
|
||||
class="bright"
|
||||
icon="icon-isTooLittle">
|
||||
</vn-icon>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
vn-click-stop="ticketDescriptor.show($event, ticket.id)"
|
||||
class="link">
|
||||
{{ticket.id}}
|
||||
</span>
|
||||
</td>
|
||||
<td name="nickname">
|
||||
<span
|
||||
title="{{ticket.nickname}}"
|
||||
vn-click-stop="clientDescriptor.show($event, ticket.clientFk)"
|
||||
class="link">
|
||||
{{ticket.nickname}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
title="{{ticket.userName}}"
|
||||
vn-click-stop="workerDescriptor.show($event, ticket.salesPersonFk)"
|
||||
class="link">
|
||||
{{ticket.userName | dashIfEmpty}}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="chip {{$ctrl.compareDate(ticket.shippedDate)}}">
|
||||
{{ticket.shippedDate | date: 'dd/MM/yyyy'}}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ticket.zoneLanding | date: 'HH:mm'}}</td>
|
||||
<td>{{ticket.practicalHour | date: 'HH:mm'}}</td>
|
||||
<td>{{ticket.shipped | date: 'HH:mm'}}</td>
|
||||
<td>{{ticket.province}}</td>
|
||||
<td>
|
||||
<span
|
||||
ng-show="ticket.refFk"
|
||||
title="{{ticket.refFk}}"
|
||||
vn-click-stop="invoiceOutDescriptor.show($event, ticket.invoiceOutId)"
|
||||
class="link">
|
||||
{{ticket.refFk}}
|
||||
</span>
|
||||
<span
|
||||
ng-show="!ticket.refFk"
|
||||
class="chip {{ticket.classColor}}">
|
||||
{{ticket.state}}
|
||||
</span>
|
||||
</td>
|
||||
<td number>
|
||||
<vn-icon
|
||||
ng-show="ticket.isFragile"
|
||||
translate-attr="{title: 'Is fragile'}"
|
||||
class="bright"
|
||||
icon="local_bar">
|
||||
</vn-icon>
|
||||
</td>
|
||||
<td name="zone">
|
||||
<span
|
||||
title="{{ticket.zoneName}}"
|
||||
vn-click-stop="zoneDescriptor.show($event, ticket.zoneFk)"
|
||||
class="link">
|
||||
{{ticket.zoneName | dashIfEmpty}}
|
||||
</span>
|
||||
</td>
|
||||
<td number>
|
||||
<span class="chip {{$ctrl.totalPriceColor(ticket)}}">
|
||||
{{(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}}
|
||||
</span>
|
||||
</td>
|
||||
<td actions>
|
||||
<vn-icon-button
|
||||
vn-anchor="{
|
||||
state: 'ticket.card.sale',
|
||||
params: {id: ticket.id},
|
||||
target: '_blank'
|
||||
}"
|
||||
vn-tooltip="Go to lines"
|
||||
icon="icon-lines">
|
||||
</vn-icon-button>
|
||||
<vn-icon-button
|
||||
vn-click-stop="$ctrl.preview(ticket)"
|
||||
vn-tooltip="Preview"
|
||||
icon="preview">
|
||||
</vn-icon-button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</slot-table>
|
||||
</smart-table>
|
||||
</vn-card>
|
||||
<vn-ticket-descriptor-popover
|
||||
vn-id="ticketDescriptor">
|
||||
</vn-ticket-descriptor-popover>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-client-descriptor-popover
|
||||
vn-id="clientDescriptor">
|
||||
</vn-client-descriptor-popover>
|
||||
<vn-zone-descriptor-popover
|
||||
vn-id="zoneDescriptor">
|
||||
</vn-zone-descriptor-popover>
|
||||
<vn-popup vn-id="summary">
|
||||
<vn-ticket-summary
|
||||
ticket="$ctrl.selectedTicket"
|
||||
model="model">
|
||||
</vn-ticket-summary>
|
||||
</vn-popup>
|
||||
<vn-contextmenu vn-id="contextmenu" targets="['vn-monitor-sales-tickets smart-table']" model="model"
|
||||
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||
<slot-menu>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.filterBySelection()">
|
||||
Filter by selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.excludeSelection()">
|
||||
Exclude selection
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isFilterAllowed()"
|
||||
ng-click="contextmenu.removeFilter()">
|
||||
Remove filter
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-click="contextmenu.removeAllFilters()">
|
||||
Remove all filters
|
||||
</vn-item>
|
||||
<vn-item translate
|
||||
ng-if="contextmenu.isActionAllowed()"
|
||||
ng-click="contextmenu.copyValue()">
|
||||
Copy value
|
||||
</vn-item>
|
||||
</slot-menu>
|
||||
</vn-contextmenu>
|
|
@ -1,178 +0,0 @@
|
|||
import ngModule from '../../module';
|
||||
import Section from 'salix/components/section';
|
||||
import './style.scss';
|
||||
|
||||
export default class Controller extends Section {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
|
||||
this.filterParams = this.fetchParams();
|
||||
this.smartTableOptions = {
|
||||
activeButtons: {
|
||||
search: true,
|
||||
shownColumns: true,
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'totalProblems',
|
||||
searchable: false
|
||||
},
|
||||
{
|
||||
field: 'salesPersonFk',
|
||||
autocomplete: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
where: `{role: 'salesPerson'}`,
|
||||
searchFunction: '{firstName: $search}',
|
||||
showField: 'nickname',
|
||||
valueField: 'id',
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'provinceFk',
|
||||
autocomplete: {
|
||||
url: 'Provinces',
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'stateFk',
|
||||
autocomplete: {
|
||||
url: 'States',
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'zoneFk',
|
||||
autocomplete: {
|
||||
url: 'Zones',
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'warehouseFk',
|
||||
autocomplete: {
|
||||
url: 'Warehouses',
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'shippedDate',
|
||||
datepicker: true
|
||||
},
|
||||
{
|
||||
field: 'theoreticalHour',
|
||||
searchable: false
|
||||
},
|
||||
{
|
||||
field: 'preparationHour',
|
||||
searchable: false
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
if (!this.$params.q) {
|
||||
this.$.$applyAsync(
|
||||
() => this.$.model.applyFilter(null, this.filterParams));
|
||||
}
|
||||
}
|
||||
|
||||
fetchParams($params = {}) {
|
||||
const excludedParams = [
|
||||
'search',
|
||||
'clientFk',
|
||||
'orderFk',
|
||||
'refFk',
|
||||
'scopeDays'
|
||||
];
|
||||
|
||||
const hasExcludedParams = excludedParams.some(param => {
|
||||
return $params && $params[param] != undefined;
|
||||
});
|
||||
const hasParams = Object.entries($params).length;
|
||||
if (!hasParams || !hasExcludedParams)
|
||||
$params.scopeDays = 1;
|
||||
|
||||
if (typeof $params.scopeDays === 'number') {
|
||||
const from = Date.vnNew();
|
||||
from.setHours(0, 0, 0, 0);
|
||||
|
||||
const to = new Date(from.getTime());
|
||||
to.setDate(to.getDate() + $params.scopeDays);
|
||||
to.setHours(23, 59, 59, 999);
|
||||
|
||||
Object.assign($params, {from, to});
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
compareDate(date) {
|
||||
let today = Date.vnNew();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
let timeTicket = new Date(date);
|
||||
timeTicket.setHours(0, 0, 0, 0);
|
||||
|
||||
let comparation = today - timeTicket;
|
||||
|
||||
if (comparation == 0)
|
||||
return 'warning';
|
||||
if (comparation < 0)
|
||||
return 'success';
|
||||
}
|
||||
|
||||
totalPriceColor(ticket) {
|
||||
const total = parseInt(ticket.totalWithVat);
|
||||
if (total > 0 && total < 50)
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
exprBuilder(param, value) {
|
||||
switch (param) {
|
||||
case 'stateFk':
|
||||
return {'ts.stateFk': value};
|
||||
case 'salesPersonFk':
|
||||
return {'c.salesPersonFk': value};
|
||||
case 'provinceFk':
|
||||
return {'a.provinceFk': value};
|
||||
case 'theoreticalHour':
|
||||
return {'z.hour': value};
|
||||
case 'practicalHour':
|
||||
return {'zed.etc': value};
|
||||
case 'shippedDate':
|
||||
return {'t.shipped': {
|
||||
between: this.dateRange(value)}
|
||||
};
|
||||
case 'nickname':
|
||||
return {[`t.nickname`]: {like: `%${value}%`}};
|
||||
case 'zoneFk':
|
||||
case 'totalWithVat':
|
||||
return {[`t.${param}`]: value};
|
||||
}
|
||||
}
|
||||
|
||||
dateRange(value) {
|
||||
const minHour = new Date(value);
|
||||
minHour.setHours(0, 0, 0, 0);
|
||||
const maxHour = new Date(value);
|
||||
maxHour.setHours(23, 59, 59, 59);
|
||||
|
||||
return [minHour, maxHour];
|
||||
}
|
||||
|
||||
preview(ticket) {
|
||||
this.selectedTicket = ticket;
|
||||
this.$.summary.show();
|
||||
}
|
||||
|
||||
autoRefresh(value) {
|
||||
if (value)
|
||||
this.refreshTimer = setInterval(() => this.$.model.refresh(), 120000);
|
||||
else {
|
||||
clearInterval(this.refreshTimer);
|
||||
this.refreshTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnMonitorSalesTickets', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -1,133 +0,0 @@
|
|||
import './index.js';
|
||||
describe('Component vnMonitorSalesTickets', () => {
|
||||
let controller;
|
||||
let $window;
|
||||
let tickets = [{
|
||||
id: 1,
|
||||
clientFk: 1,
|
||||
checked: false,
|
||||
totalWithVat: 10.5
|
||||
}, {
|
||||
id: 2,
|
||||
clientFk: 1,
|
||||
checked: true,
|
||||
totalWithVat: 20.5
|
||||
}, {
|
||||
id: 3,
|
||||
clientFk: 1,
|
||||
checked: true,
|
||||
totalWithVat: 30
|
||||
}];
|
||||
|
||||
beforeEach(ngModule('monitor'));
|
||||
|
||||
beforeEach(inject(($componentController, _$window_) => {
|
||||
$window = _$window_;
|
||||
const $element = angular.element('<vn-monitor-sales-tickets></vn-monitor-sales-tickets>');
|
||||
controller = $componentController('vnMonitorSalesTickets', {$element});
|
||||
}));
|
||||
|
||||
describe('fetchParams()', () => {
|
||||
it('should return a range of dates with passed scope days', () => {
|
||||
let params = controller.fetchParams({
|
||||
scopeDays: 2
|
||||
});
|
||||
const from = Date.vnNew();
|
||||
from.setHours(0, 0, 0, 0);
|
||||
const to = new Date(from.getTime());
|
||||
to.setDate(to.getDate() + params.scopeDays);
|
||||
to.setHours(23, 59, 59, 999);
|
||||
|
||||
const expectedParams = {
|
||||
from,
|
||||
scopeDays: params.scopeDays,
|
||||
to
|
||||
};
|
||||
|
||||
expect(params).toEqual(expectedParams);
|
||||
});
|
||||
|
||||
it('should return default value for scope days', () => {
|
||||
let params = controller.fetchParams({
|
||||
scopeDays: 1
|
||||
});
|
||||
|
||||
expect(params.scopeDays).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return the given scope days', () => {
|
||||
let params = controller.fetchParams({
|
||||
scopeDays: 2
|
||||
});
|
||||
|
||||
expect(params.scopeDays).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('compareDate()', () => {
|
||||
it('should return warning when the date is the present', () => {
|
||||
let today = Date.vnNew();
|
||||
let result = controller.compareDate(today);
|
||||
|
||||
expect(result).toEqual('warning');
|
||||
});
|
||||
|
||||
it('should return sucess when the date is in the future', () => {
|
||||
let futureDate = Date.vnNew();
|
||||
futureDate = futureDate.setDate(futureDate.getDate() + 10);
|
||||
let result = controller.compareDate(futureDate);
|
||||
|
||||
expect(result).toEqual('success');
|
||||
});
|
||||
|
||||
it('should return undefined when the date is in the past', () => {
|
||||
let pastDate = Date.vnNew();
|
||||
pastDate = pastDate.setDate(pastDate.getDate() - 10);
|
||||
let result = controller.compareDate(pastDate);
|
||||
|
||||
expect(result).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('totalPriceColor()', () => {
|
||||
it('should return "warning" when the ticket amount is less than 50€', () => {
|
||||
const result = controller.totalPriceColor({totalWithVat: '8.50'});
|
||||
|
||||
expect(result).toEqual('warning');
|
||||
});
|
||||
});
|
||||
|
||||
describe('dateRange()', () => {
|
||||
it('should return two dates with the hours at the start and end of the given date', () => {
|
||||
const now = Date.vnNew();
|
||||
|
||||
const today = now.getDate();
|
||||
|
||||
const dateRange = controller.dateRange(now);
|
||||
const start = dateRange[0].toString();
|
||||
const end = dateRange[1].toString();
|
||||
|
||||
expect(start).toContain(today);
|
||||
expect(start).toContain('00:00:00');
|
||||
|
||||
expect(end).toContain(today);
|
||||
expect(end).toContain('23:59:59');
|
||||
});
|
||||
});
|
||||
|
||||
describe('preview()', () => {
|
||||
it('should show the dialog summary', () => {
|
||||
controller.$.summary = {show: () => {}};
|
||||
jest.spyOn(controller.$.summary, 'show');
|
||||
|
||||
let event = new MouseEvent('click', {
|
||||
view: $window,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
controller.preview(event, tickets[0]);
|
||||
|
||||
expect(controller.$.summary.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,47 +0,0 @@
|
|||
@import "variables";
|
||||
|
||||
vn-monitor-sales-tickets {
|
||||
@media screen and (max-width: 1440px) {
|
||||
.expendable {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
vn-th.icon-field,
|
||||
vn-th.icon-field *,
|
||||
vn-td.icon-field,
|
||||
vn-td.icon-field * {
|
||||
padding: 0;
|
||||
max-width: 50px
|
||||
}
|
||||
|
||||
vn-th[field="nickname"],
|
||||
vn-td[name="nickname"] {
|
||||
min-width: 250px
|
||||
}
|
||||
|
||||
vn-td.icon-field > vn-icon {
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
vn-table.scrollable.lg {
|
||||
height: 736px
|
||||
}
|
||||
|
||||
tbody tr[ng-repeat]:focus {
|
||||
background-color: $color-primary-light
|
||||
}
|
||||
|
||||
.highRisk i {
|
||||
color: $color-alert
|
||||
}
|
||||
|
||||
td[name="nickname"] {
|
||||
max-width: 200px
|
||||
}
|
||||
|
||||
td[name="zone"] {
|
||||
max-width: 150px
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Sales monitor: Monitor de ventas
|
|
@ -1,4 +0,0 @@
|
|||
<vn-portal slot="menu">
|
||||
<vn-left-menu></vn-left-menu>
|
||||
</vn-portal>
|
||||
<ui-view></ui-view>
|
|
@ -1,7 +1,16 @@
|
|||
import ngModule from '../module';
|
||||
import ModuleMain from 'salix/components/module-main';
|
||||
|
||||
export default class Monitor extends ModuleMain {}
|
||||
export default class Monitor extends ModuleMain {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
}
|
||||
|
||||
async $onInit() {
|
||||
this.$state.go('home');
|
||||
window.location.href = await this.vnApp.getUrl(`monitor/`);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnMonitor', {
|
||||
controller: Monitor,
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
{
|
||||
"module": "monitor",
|
||||
"name": "Monitors",
|
||||
"icon" : "grid_view",
|
||||
"dependencies": ["ticket", "worker", "client"],
|
||||
"validations" : true,
|
||||
"icon": "grid_view",
|
||||
"menus": {
|
||||
"main": [
|
||||
{"state": "monitor.index", "icon": "grid_view"}
|
||||
],
|
||||
"main": [],
|
||||
"card": []
|
||||
},
|
||||
"keybindings": [
|
||||
|
|
Loading…
Reference in New Issue