2569 - Section changes
gitea/salix/pipeline/head There was a failure building this commit Details

This commit is contained in:
Joan Sanchez 2020-11-20 15:05:57 +01:00
parent f4e9fc83ec
commit 7693a1c449
25 changed files with 635 additions and 173 deletions

View File

@ -20,6 +20,9 @@
"Container": {
"dataSource": "storage"
},
"Continent": {
"dataSource": "vn"
},
"Collection": {
"dataSource": "vn"
},

View File

@ -0,0 +1,27 @@
{
"name": "Continent",
"base": "VnModel",
"options": {
"mysql": {
"table": "continent"
}
},
"properties": {
"id": {
"type": "number"
},
"name": {
"type": "string"
},
"code": {
"id": true,
"type": "string"
}
},
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}]
}

View File

@ -0,0 +1,20 @@
CREATE TABLE `vn`.continent
(
id TINYINT(4) AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
code VARCHAR(2) NOT NULL COLLATE utf8_general_ci,
CONSTRAINT continent_pk
PRIMARY KEY (id)
)
COMMENT 'World continents';
CREATE UNIQUE INDEX continent_name_uindex
ON `vn`.continent (name);
INSERT IGNORE INTO `vn`.continent (`name`, `code`)
VALUES
('Asia', 'AS'),
('América', 'AM'),
('África', 'AF'),
('Europa', 'EU'),
('Oceanía', 'OC');

View File

@ -0,0 +1,13 @@
ALTER TABLE `vn`.`country`
ADD COLUMN `continentFk` TINYINT(4) NULL AFTER `ibanLength`,
ADD INDEX `continent_id_fk_idx` (`continentFk` ASC);
ALTER TABLE `vn`.`country`
ADD CONSTRAINT `continent_id_fk`
FOREIGN KEY (`continentFk`)
REFERENCES `vn`.`continent` (`id`)
ON DELETE NO ACTION
ON UPDATE CASCADE;
UPDATE `vn`.`country` SET `continentFk` = '2' WHERE (`id` = '11');
UPDATE `vn`.`country` SET `continentFk` = '2' WHERE (`id` = '13');

View File

@ -3,3 +3,4 @@ host = localhost
port = 3306
user = root
password = root
default-character-set=utf8

View File

@ -92,17 +92,17 @@ INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossF
(109, 'HLK', 'Bruce' , 'Banner', 109, 19, 432978109),
(110, 'JJJ', 'Jessica' , 'Jones' , 110, 19, 432978110);
INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`)
INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`, `continentFk`)
VALUES
(1, 'España', 1, 'ES', 1, 24),
(2, 'Italia', 1, 'IT', 1, 27),
(3, 'Alemania', 1, 'DE', 1, 22),
(4, 'Rumania', 1, 'RO', 1, 24),
(5, 'Holanda', 1, 'NL', 1, 18),
(8, 'Portugal', 1, 'PT', 1, 27),
(13,'Ecuador', 0, 'EC', 1, 24),
(19,'Francia', 1, 'FR', 1, 27),
(30,'Canarias', 1, 'IC', 1, 24);
(1, 'España', 1, 'ES', 1, 24, 4),
(2, 'Italia', 1, 'IT', 1, 27, 4),
(3, 'Alemania', 1, 'DE', 1, 22, 4),
(4, 'Rumania', 1, 'RO', 1, 24, 4),
(5, 'Holanda', 1, 'NL', 1, 18, 4),
(8, 'Portugal', 1, 'PT', 1, 27, 4),
(13,'Ecuador', 0, 'EC', 1, 24, 2),
(19,'Francia', 1, 'FR', 1, 27, 4),
(30,'Canarias', 1, 'IC', 1, 24, 4);
INSERT INTO `hedera`.`language` (`code`, `name`, `orgName`, `isActive`)
VALUES
@ -118,13 +118,13 @@ INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
(1, 'Main Warehouse'),
(2, 'Silla');
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`, `hasComission`, `aliasFk`)
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`, `hasComission`, `aliasFk`, `countryFk`)
VALUES
(1, 'Warehouse One', 1, 1, 1, 1, 1, 1, 1, 2),
(2, 'Warehouse Two', 1, 1, 1, 1, 0, 0, 1, 2),
(3, 'Warehouse Three', 1, 1, 1, 1, 0, 0, 0, 2),
(4, 'Warehouse Four', 1, 1, 1, 1, 0, 0, 0, 2),
(5, 'Warehouse Five', 1, 1, 1, 1, 0, 0, 0, 2);
(1, 'Warehouse One', 1, 1, 1, 1, 1, 1, 1, 2, 1),
(2, 'Warehouse Two', 1, 1, 1, 1, 0, 0, 1, 2, 13),
(3, 'Warehouse Three', 1, 1, 1, 1, 0, 0, 0, 2, 1),
(4, 'Warehouse Four', 1, 1, 1, 1, 0, 0, 0, 2, 1),
(5, 'Warehouse Five', 1, 1, 1, 1, 0, 0, 0, 2, 1);
INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPreparedByPacking`, `code`, `pickingPlacement`, `path`)
VALUES
@ -1250,11 +1250,11 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO
(1, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1),
(2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2),
(3, CURDATE(), CURDATE(), 1, 2, 1, 0.00, 0.00, 'third travel', 1, 1),
(4, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 50.00, 500, 'fourth travel', 0, 2),
(5, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 2, 1, 50.00, 500, 'fifth travel', 1, 1),
(6, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 2, 1, 50.00, 500, 'sixth travel', 1, 2),
(7, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'seventh travel', 2, 1),
(8, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 2, 1, 50.00, 500, 'eight travel', 1, 2);
(4, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 3, 1, 50.00, 500, 'fourth travel', 0, 2),
(5, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 3, 3, 1, 50.00, 500, 'fifth travel', 1, 1),
(6, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 50.00, 500, 'sixth travel', 1, 2),
(7, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1),
(8, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2);
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `ref`,`isInventory`, `isRaid`, `notes`, `evaNotes`)
VALUES

View File

@ -1 +1,3 @@
<div></div>
<div translate>
<ng-transclude></ng-transclude>
</div>

View File

@ -1,19 +1,10 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import './style.scss';
export default class Th extends Component {
constructor($element, $, $transclude) {
super($element, $);
export default class Th {
constructor($element) {
this._order = 'ASC';
this.column = $element[0];
$element.on('click', () => this.onToggleOrder());
$transclude($clone => {
const text = this.$t($clone.text()); // Not updating translations
$element.append(text ? text : $clone);
});
}
/**
@ -81,9 +72,10 @@ export default class Th extends Component {
}
}
Th.$inject = ['$element', '$scope', '$transclude'];
Th.$inject = ['$element'];
ngModule.vnComponent('vnTh', {
template: require('./index.html'),
transclude: true,
controller: Th,
bindings: {

View File

@ -6,18 +6,18 @@ vn-th {
}
vn-th[field] {
&.active:after {
&.active > :after {
color: $color-font;
opacity: 1;
}
&.desc:after {
&.desc > :after {
content: 'arrow_drop_down';
}
&.asc:after {
&.asc > :after {
content: 'arrow_drop_up';
}
&:after {
& > :after {
font-family: 'Material Icons';
content: 'arrow_drop_down';
position: absolute;
@ -27,7 +27,7 @@ vn-th[field] {
opacity: 0
}
&:hover:after {
&:hover > :after {
opacity: 1;
}
}

View File

@ -17,7 +17,7 @@
ui-sref="{{::$ctrl.summaryState}}({id: $ctrl.descriptor.id})">
<vn-icon icon="desktop_windows"></vn-icon>
</a>
<vn-icon-button ng-if="$ctrl.$transclude.isSlotFilled('menu')"
<vn-icon-button ng-if="!$ctrl.$transclude.isSlotFilled('dotMenu')"
ng-class="::{invisible: !$ctrl.$transclude.isSlotFilled('menu')}"
icon="more_vert"
vn-popover="menu">

View File

@ -84,6 +84,32 @@ class VnMySQL extends MySQL {
return wrappedConnector.buildWhere(null, where);
}
/**
* Constructs SQL GROUP BY clause from Loopback filter.
*
* @param {Object} group The group by definition
* @return {String} Built SQL group by
*/
makeGroupBy(group) {
if (!group)
return '';
if (typeof group === 'string')
group = [group];
let clauses = [];
for (let clause of group) {
let sqlGroup = '';
let t = clause.split(/[\s,]+/);
sqlGroup += this.escapeName(t[0]);
clauses.push(sqlGroup);
}
return `GROUP BY ${clauses.join(', ')}`;
}
/**
* Constructs SQL order clause from Loopback filter.
*

View File

@ -5,10 +5,8 @@ describe('item getBalance()', () => {
let params = {where: {itemFk: 1, warehouseFk: 2}};
let result = await app.models.Item.getBalance(params);
expect(result.length).toBe(4);
expect(result.length).toBe(2);
expect(result[0].balance).toBe(-100);
expect(result[1].balance).toBe(-110);
expect(result[2].balance).toBe(-110);
expect(result[3].balance).toBe(-210);
expect(result[1].balance).toBe(-200);
});
});

View File

@ -67,6 +67,10 @@ module.exports = Self => {
arg: 'ref',
type: 'string',
description: 'The reference'
}, {
arg: 'continent',
type: 'string',
description: 'The continent code'
}
],
returns: {
@ -97,6 +101,8 @@ module.exports = Self => {
return {'t.landed': {gte: value}};
case 'landedTo':
return {'t.landed': {lte: value}};
case 'continent':
return {'cnt.code': value};
case 'id':
case 'agencyFk':
case 'warehouseOutFk':
@ -107,17 +113,21 @@ module.exports = Self => {
}
});
filter = mergeFilters(ctx.args.filter, {where});
filter = mergeFilters(filter, {where});
let stmts = [];
let stmt;
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.travel');
stmt = new ParameterizedSQL(
`SELECT
tr.id,
tr.ref,
tr.shipped,
tr.landed,
tr.kg,
`CREATE TEMPORARY TABLE tmp.travel
(INDEX (id))
ENGINE = MEMORY
SELECT
t.id,
t.ref,
t.shipped,
t.landed,
t.kg,
am.id AS agencyModeFk,
am.name AS agencyModeName,
wo.id AS warehouseOutFk,
@ -126,102 +136,78 @@ module.exports = Self => {
w.name AS warehouseInName,
SUM(b.stickers) AS stickers,
s.id AS supplierFk,
s.nickname AS supplierNickname
FROM travel tr
LEFT JOIN supplier s ON s.id = tr.cargoSupplierFk
LEFT JOIN entry e ON e.travelFk = tr.id
s.nickname AS cargoSupplierNickname,
CAST(SUM(i.density * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as loadedKg,
CAST(SUM(167.5 * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as volumeKg
FROM travel t
LEFT JOIN supplier s ON s.id = t.cargoSupplierFk
LEFT JOIN entry e ON e.travelFk = t.id
LEFT JOIN buy b ON b.entryFk = e.id
LEFT JOIN packaging p ON p.id = b.packageFk
LEFT JOIN packaging pkg ON pkg.id = b.packageFk
LEFT JOIN item i ON i.id = b.itemFk
LEFT JOIN itemType it ON it.id = i.typeFk
JOIN warehouse w ON w.id = tr.warehouseInFk
JOIN warehouse wo ON wo.id = tr.warehouseOutFk
JOIN agencyMode am ON am.id = tr.agencyFk`
JOIN warehouse w ON w.id = t.warehouseInFk
JOIN warehouse wo ON wo.id = t.warehouseOutFk
JOIN country c ON c.id = wo.countryFk
LEFT JOIN continent cnt ON cnt.id = c.continentFk
JOIN agencyMode am ON am.id = t.agencyFk`
);
/* cast(sum(a.density * c.Etiquetas * IF(cb.Volumen, cb.Volumen, cb.X * cb.Y * cb.Z) / 1000000 ) as DECIMAL(10,0)) as loadedKg,
cast(sum(167.5 * c.Etiquetas * IF(cb.Volumen, cb.Volumen, cb.X * cb.Y * cb.Z) / 1000000 ) as DECIMAL(10,0)) as volumeKg,
pc.Alias as Carguera */
stmt.merge(conn.makeWhere(filter.where));
stmt.merge(conn.makeGroupBy('t.id'));
stmt.merge(conn.makeLimit(filter));
stmts.push(stmt);
// WHERE tr.landing >= @vDateFrom AND (wo.name="Colombia" OR wo.name="Ecuador")
const travelsIndex = stmts.push('SELECT * FROM tmp.travel') - 1;
stmt.merge('GROUP BY tr.id');
// stmt.merge(conn.makeSuffix(filter));
const itemsIndex = stmts.push(stmt) - 1;
stmt = new ParameterizedSQL(
`SELECT
e.id,
e.travelFk,
e.ref,
e.loadPriority,
s.name AS supplierName,
SUM(b.stickers) AS stickers,
e.evaNotes,
e.notes,
CAST(SUM(i.density * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as loadedkg,
CAST(SUM(167.5 * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000 ) as DECIMAL(10,0)) as volumeKg
FROM entry e
JOIN tmp.travel tr ON tr.id = e.travelFk
JOIN buy b ON b.entryFk = e.id
JOIN packaging pkg ON pkg.id = b.packageFk
JOIN item i ON i.id = b.itemFk
JOIN itemType it ON it.id = i.typeFk
JOIN supplier s ON s.id = e.supplierFk`
);
stmt.merge(conn.makeGroupBy('e.id'));
stmt.merge(conn.makeOrderBy(filter.order));
const entriesIndex = stmts.push(stmt) - 1;
stmts.push(`DROP TEMPORARY TABLE tmp.travel`);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql);
return itemsIndex === 0 ? result : result[itemsIndex];
/*
SET @vDateFrom:= TIMESTAMPADD(WEEK,-12,CURDATE());
const travels = result[travelsIndex];
const entries = result[entriesIndex];
SELECT
1 as IsTravel,
tr.id as travel,
NULL as Entrada,
ag.Agencia,
tr.ref,
tr.shipment,
wo.name as OrigenCajas,
tr.landing,
w.name as Destino,
sum(c.Etiquetas) as Etiquetas,
NULL as Notas_Eva,
kg,
cast(sum(a.density * c.Etiquetas * IF(cb.Volumen, cb.Volumen, cb.X * cb.Y * cb.Z) / 1000000 ) as DECIMAL(10,0)) as loadedKg,
cast(sum(167.5 * c.Etiquetas * IF(cb.Volumen, cb.Volumen, cb.X * cb.Y * cb.Z) / 1000000 ) as DECIMAL(10,0)) as volumeKg,
NULL as loadPriority,
NULL as Notas,
pc.Alias as Carguera
FROM travel tr
LEFT JOIN Proveedores pc ON pc.Id_Proveedor = tr.cargoSupplierFk
LEFT JOIN Entradas e ON e.travel_id = tr.id
LEFT JOIN Compres c ON c.Id_Entrada = e.Id_Entrada
LEFT JOIN Cubos cb ON cb.Id_Cubo = c.Id_Cubo
LEFT JOIN Articles a ON a.Id_Article = c.Id_Article
LEFT JOIN Tipos tp ON tp.tipo_id = a.tipo_id
JOIN warehouse w ON w.id = tr.warehouse_id
JOIN warehouse wo ON wo.id = tr.warehouse_id_out
JOIN Agencias ag ON ag.Id_Agencia = tr.agency_id
WHERE tr.landing >= @vDateFrom AND (wo.name="Colombia" OR wo.name="Ecuador")
GROUP BY tr.id
const travelsMap = new Map();
for (let travel of travels)
travelsMap.set(travel.id, travel);
UNION ALL
for (let entry of entries) {
const travel = travelsMap.get(entry.travelFk);
SELECT
0 as IsTravel,
e.travel_id as travel,
e.Id_Entrada,
p.Proveedor,
e.Referencia,
tr.shipment,
wo.name as OrigenCajas,
tr.landing,
w.name as Destino,
sum(Etiquetas) as Etiquetas,
e.Notas_Eva,
NULL as kg,
cast(sum(a.density * c.Etiquetas * IF(cb.Volumen, cb.Volumen, cb.X * cb.Y * cb.Z) / 1000000 ) as DECIMAL(10,0)) as loadedkg,
cast(sum(167.5 * c.Etiquetas * IF(cb.Volumen, cb.Volumen, cb.X * cb.Y * cb.Z) / 1000000 ) as DECIMAL(10,0)) as volumeKg,
loadPriority,
e.Notas,
pc.Alias as carguera
if (travel) {
if (!travel.entries) travel.entries = [];
FROM Entradas e
JOIN Compres c ON c.Id_Entrada = e.Id_Entrada
JOIN Cubos cb ON cb.Id_Cubo = c.Id_Cubo
JOIN Articles a ON a.Id_Article = c.Id_Article
JOIN Tipos tp ON tp.tipo_id = a.tipo_id
JOIN Proveedores p ON p.Id_Proveedor = e.Id_Proveedor
JOIN travel tr ON tr.id = e.travel_id
LEFT JOIN Proveedores pc ON pc.Id_Proveedor = tr.cargoSupplierFk
JOIN warehouse w ON w.id = tr.warehouse_id
JOIN warehouse wo ON wo.id = tr.warehouse_id_out
WHERE tr.landing >= @vDateFrom AND (wo.name="Colombia" OR wo.name="Ecuador")
GROUP BY e.Id_Entrada
) sub
ORDER BY landing ASC, shipment ASC,travel, IsTravel DESC, (loadPriority > 0) DESC,loadPriority, Agencia, Notas_Eva ; */
travel.entries.push(entry);
}
}
return travels;
};
};

View File

@ -0,0 +1,66 @@
const app = require('vn-loopback/server/server');
describe('Travel extraCommunityFilter()', () => {
const filter = {
order: 'landed ASC, shipped ASC, travelFk, loadPriority, agencyModeFk, evaNotes',
};
it('should return the travel matching "search"', async() => {
const ctx = {
args: {
search: 2
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
const firstRow = result[0];
const entries = firstRow.entries;
expect(result.length).toEqual(1);
expect(firstRow.id).toEqual(2);
expect(entries.length).toEqual(2);
});
it('should return the travel matching "search" by ref', async() => {
const ctx = {
args: {
search: 'third'
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
const firstRow = result[0];
expect(result.length).toEqual(1);
expect(firstRow.id).toEqual(3);
});
it('should return the travel matching "warehouse out"', async() => {
const ctx = {
args: {
warehouseOutFk: 2
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
expect(result.length).toEqual(3);
});
it('should return the routes matching "landed from" and "landed to"', async() => {
const from = new Date();
const to = new Date();
from.setHours(0, 0, 0, 0);
to.setHours(23, 59, 59, 999);
to.setDate(to.getDate() + 14);
const ctx = {
args: {
landedFrom: from,
landedTo: to
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
expect(result.length).toEqual(1);
});
});

View File

@ -1,6 +1,6 @@
Reference: Referencia
Wh. In: Almacén entrada
Wh. Out: Almacén salida
Wh. In: Alm. entrada
Wh. Out: Alm. salida
Shipped: F. envío
Landed: F. entrega
Total entries: Entradas totales

View File

@ -0,0 +1,91 @@
<div class="search-panel">
<form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-textfield
vn-one
label="General search"
ng-model="filter.search"
info="Search travels by id"
vn-focus>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Reference"
ng-model="filter.ref">
</vn-textfield>
<vn-textfield
vn-one
label="Total entries"
ng-model="filter.totalEntries">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Travel id"
ng-model="filter.id">
</vn-textfield>
<vn-autocomplete vn-one
label="Agency"
ng-model="filter.agencyFk"
url="AgencyModes"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker
vn-one
label="Shipped from"
ng-model="filter.shippedFrom">
</vn-date-picker>
<vn-date-picker
vn-one
label="Shipped to"
ng-model="filter.shippedTo">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker
vn-one
label="Landed from"
ng-model="filter.landedFrom">
</vn-date-picker>
<vn-date-picker
vn-one
label="Landed to"
ng-model="filter.landedTo">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
label="Warehouse In"
ng-model="filter.warehouseInFk"
url="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
<vn-autocomplete vn-one
label="Warehouse Out"
ng-model="filter.warehouseOutFk"
url="Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
label="Continent Out"
ng-model="filter.continent"
url="Continents"
show-field="name"
value-field="code">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">
<vn-submit label="Search"></vn-submit>
</vn-horizontal>
</form>
</div>

View File

@ -0,0 +1,7 @@
import ngModule from '../module';
import SearchPanel from 'core/components/searchbar/search-panel';
ngModule.vnComponent('vnExtraCommunitySearchPanel', {
template: require('./index.html'),
controller: SearchPanel
});

View File

@ -1,49 +1,111 @@
<vn-crud-model auto-load="true"
vn-id="model"
url="Travels/extraCommunityFilter"
data="travels">
data="travels"
order="landed ASC, shipped ASC, travelFk, loadPriority, agencyModeFk, evaNotes"
limit="20">
</vn-crud-model>
<vn-portal slot="topbar">
<vn-searchbar
vn-focus
placeholder="Search by travel id"
info="Search by travel id"
panel="vn-extra-community-search-panel"
suggested-filter="$ctrl.defaultFilter"
filter="$ctrl.defaultFilter"
info="Search by travel id or reference"
auto-state="false"
model="model">
</vn-searchbar>
</vn-portal>
<vn-data-viewer model="model">
<vn-card>
<section ng-repeat="travel in travels" class="vn-pa-md">
<vn-horizontal class="header">
<vn-table>
<vn-data-viewer model="model" class="travel-list">
<vn-card ng-repeat="travel in travels" class="vn-mb-md">
<section class="vn-pa-md">
<vn-table vn-droppable="$ctrl.onDrop($event)" ng-attr-id="{{::travel.id}}">
<vn-thead>
<vn-tr>
<vn-th>{{travel.id}}</vn-th>
<vn-th>{{travel.supplierNickname}}</vn-th>
</vn-tr>
</vn-thead>
</vn-table>
<!-- <h5><span></span></h5> -->
</vn-horizontal>
<!-- <vn-table>
<vn-thead>
<vn-tr>
<vn-th class="waste-family">Family</vn-th>
<vn-th number>Percentage</vn-th>
<vn-th number>Dwindle</vn-th>
<vn-th number>Total</vn-th>
<vn-tr ng-if="$index == 0">
<vn-th shrink>Id</vn-th>
<vn-th expand>Supplier</vn-th>
<vn-th expand>Freighter</vn-th>
<vn-th>Reference</vn-th>
<vn-th number>Packages</vn-th>
<vn-th number>Bl. KG</vn-th>
<vn-th number>Phy. KG</vn-th>
<vn-th number>Vol. KG</vn-th>
<vn-th expand translate-attr="{title: 'Warehouse Out'}">
Wh. Out
</vn-th>
<vn-th expand>Shipped</vn-th>
<vn-th expand translate-attr="{title: 'Warehouse In'}">
Wh. In
</vn-th>
<vn-th expand>Landed</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="waste in detail.lines">
<vn-td class="waste-family">{{::waste.family}}</vn-td>
<vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td>
<vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td>
<vn-td number>{{::waste.total | currency: 'EUR'}}</vn-td>
<vn-tr class="header">
<vn-td>
<span class="link"
ng-click="travelDescriptor.show($event, travel.id)">
{{::travel.id}}
</span>
</vn-td>
<vn-td expand>{{::travel.agencyModeName}}</vn-td>
<vn-td expand>{{::travel.cargoSupplierNickname}}</vn-td>
<vn-td-editable expand>
<text>{{travel.ref}}</text>
<field>
<vn-textfield class="dense" vn-focus
ng-model="travel.ref"
on-change="$ctrl.changeReference(travel)">
</vn-textfield>
</field>
</vn-td-editable>
<vn-td number>{{::travel.stickers}}</vn-td>
<vn-td number>{{::travel.kg}}</vn-td>
<vn-td number>{{::travel.loadedKg}}</vn-td>
<vn-td number>{{::travel.volumeKg}}</vn-td>
<vn-td expand>{{::travel.warehouseOutName}}</vn-td>
<vn-td expand>{{::travel.shipped | date: 'dd/MM/yyyy'}}</vn-td>
<vn-td expand>{{::travel.warehouseInName}}</vn-td>
<vn-td expand>{{::travel.landed | date: 'dd/MM/yyyy'}}</vn-td>
</vn-tr>
<a href="#" ng-repeat="entry in travel.entries" class="vn-tr" draggable
ng-attr-id="{{::entry.id}}"
ng-click="$event.preventDefault()">
<vn-td>
<span class="link"
ng-click="entryDescriptor.show($event, entry.id)">
{{::entry.id}}
</span>
</vn-td>
<vn-td>{{::entry.supplierName}}</vn-td>
<vn-td></vn-td>
<vn-td expand>{{::entry.ref}}</vn-td>
<vn-th number>{{::entry.stickers}}</vn-th>
<vn-td number></vn-td>
<vn-td number>{{::entry.loadedkg}}</vn-td>
<vn-td number>{{::entry.volumeKg}}</vn-td>
<vn-td>
<span nf-if="::entry.notes" vn-tooltip="{{::entry.notes}}">
{{::entry.notes}}
</span>
</vn-td>
<vn-td>
<span nf-if="::entry.evaNotes" vn-tooltip="{{::entry.evaNotes}}">
{{::entry.evaNotes}}
</span>
</vn-td>
<vn-td></vn-td>
<vn-td></vn-td>
</a>
</vn-tbody>
</vn-table> -->
</vn-table>
</section>
</vn-card>
</vn-data-viewer>
<vn-travel-descriptor-popover
vn-id="travelDescriptor">
</vn-travel-descriptor-popover>
<vn-entry-descriptor-popover
vn-id="entryDescriptor">
</vn-entry-descriptor-popover>

View File

@ -2,7 +2,90 @@ import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss';
class Controller extends Section {
constructor($element, $) {
super($element, $);
const draggable = this.element.querySelector('.travel-list');
draggable.addEventListener('dragstart',
event => this.dragStart(event));
draggable.addEventListener('dragend',
event => this.dragEnd(event));
this.draggableElement = 'a[draggable]';
this.droppableElement = 'vn-table[vn-droppable]';
const scopeDays = 14;
const landedFrom = new Date();
landedFrom.setHours(0, 0, 0, 0);
const landedTo = new Date();
landedTo.setDate(landedTo.getDate() + scopeDays);
landedTo.setHours(23, 59, 59, 59);
this.defaultFilter = {
landedFrom: landedFrom,
landedTo: landedTo,
continent: 'AM'
};
}
findDraggable($event) {
const target = $event.target;
const draggable = target.closest(this.draggableElement);
return draggable;
}
findDroppable($event) {
const target = $event.target;
const droppable = target.closest(this.droppableElement);
return droppable;
}
dragStart($event) {
const draggable = this.findDraggable($event);
draggable.classList.add('dragging');
const id = draggable.getAttribute('id');
this.entryId = id;
this.entry = draggable;
}
dragEnd($event) {
const draggable = this.findDraggable($event);
draggable.classList.remove('dragging');
this.entryId = null;
this.entry = null;
}
onDrop($event) {
const model = this.$.model;
const droppable = this.findDroppable($event);
const travelId = droppable.getAttribute('id');
const currentDroppable = this.entry.closest(this.droppableElement);
if (currentDroppable == droppable) return;
if (this.entryId && travelId) {
const path = `Entries/${this.entryId}`;
this.$http.patch(path, {travelFk: travelId})
.then(() => model.refresh())
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
}
}
changeReference(travel) {
const params = {ref: travel.ref};
const endpoint = `Travels/${travel.id}`;
this.$http.patch(endpoint, params)
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
}
}
ngModule.vnComponent('vnTravelExtraCommunity', {
template: require('./index.html'),
controller: Section
controller: Controller
});

View File

@ -0,0 +1,47 @@
import './index.js';
describe('Travel Component vnTravelExtraCommunity', () => {
let controller;
let $httpBackend;
let travel = {
id: 1,
warehouseInFk: 1,
totalEntries: 3,
isDelivered: false
};
beforeEach(ngModule('travel'));
beforeEach(inject(($componentController, _$httpBackend_) => {
$httpBackend = _$httpBackend_;
const $element = angular.element('<vn-travel-extra-community></vn-travel-extra-community>');
controller = $componentController('vnTravelExtraCommunity', {$element});
controller.$.summary = {show: jasmine.createSpy('show')};
}));
describe('changeReference()', () => {
it('should make an HTTP query', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
const travel = {id: 1, ref: 'New reference'};
const expectedData = {ref: 'New reference'};
$httpBackend.expect('PATCH', `Travels/${travel.id}`, expectedData).respond(200);
controller.changeReference(travel);
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
});
});
xdescribe('changeReference()', () => {
it('should make an HTTP query', () => {
let event = new MouseEvent('click', {
bubbles: true,
cancelable: true
});
controller.preview(event, travel);
expect(controller.$.summary.show).toHaveBeenCalledWith();
});
});
});

View File

@ -1 +1,8 @@
Family: Familia
Extra community: Extra comunitarios
Freighter: Transitario
Bl. KG: KG Bloq.
Phy. KG: KG físico
Vol. KG: KG Vol.
Search by travel id or reference: Buscar por id travel o referencia
Continent Out: Continente salida

View File

@ -3,7 +3,6 @@
vn-travel-extra-community {
.header {
margin-bottom: 16px;
text-transform: uppercase;
font-size: 1.25rem;
line-height: 1;
padding: 7px;
@ -11,15 +10,46 @@ vn-travel-extra-community {
padding-bottom: 4px;
font-weight: lighter;
background-color: #fde6ca;
color: $color-font-light;
border-bottom: 1px solid #f7931e;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
vn-table vn-th.waste-family,
vn-table vn-td.waste-family {
max-width: 64px;
width: 64px
vn-td-editable text {
background-color: transparent;
padding: 0;
border: 0;
border-bottom: 1px dashed $color-active;
border-radius: 0;
color: $color-active
}
vn-td-editable text:after {
font-family: 'Material Icons';
content: 'edit';
position: absolute;
margin-left: 5px;
color: $color-spacer
}
vn-table[vn-droppable] {
border-radius: 0;
}
a[draggable] {
transition: all .5s;
cursor: move;
outline: 0;
}
a[draggable]:hover {
background-color: $color-hover-cd
}
a[draggable].dragging {
background-color: $color-success-light;
font-weight:bold
}
}

View File

@ -14,3 +14,4 @@ import './thermograph/create/';
import './thermograph/edit/';
import './descriptor-popover';
import './extra-community';
import './extra-community-search-panel';

View File

@ -93,7 +93,7 @@
"acl": ["buyer"]
},
{
"url": "/extra-community",
"url": "/extra-community?q",
"state": "travel.extraCommunity",
"component": "vn-travel-extra-community",
"description": "Extra community",

View File

@ -1,6 +1,6 @@
Reference: Referencia
Warehouse In: Almacen entrada
Warehouse Out: Almacen salida
Warehouse In: Almacén entrada
Warehouse Out: Almacén salida
Shipped: F. envío
Landed: F. entrega
Total entries: Entradas totales