Spinner, filtros catalogo

This commit is contained in:
Juan Ferrer Toribio 2015-11-19 14:57:23 +01:00
parent 4b015714c0
commit dc64142141
53 changed files with 1304 additions and 948 deletions

View File

@ -141,8 +141,8 @@ class Web
,$conf['db']['schema']
,$conf['db']['port']
);
self::$conn->query ('CALL user_session_start (#)',
[session_id ()]);
self::$conn->query ('CALL user_session_start (#)', [session_id ()]);
self::$conn->query ('SET @lang = #', [\Vn\Lib\Locale::get ()]);
Auth::login ($useCookies);
}

View File

@ -25,387 +25,18 @@ Vn.Shelves = new Class
,onPreviewClick: function ()
{
var batch = new Sql.Batch ();
batch.addParams ({
'shelf': this.$('shelf'),
'wh': this.$('warehouse'),
'date': this.$('date'),
'family': this.$('family'),
'filter': this.$('filter')
batch.addValues ({
'shelf': this.$('shelf').value,
'wh': this.$('warehouse').value,
'date': this.$('date').value,
'family': this.$('family').value,
'filter': this.$('filter').value,
'title': this.$('report-title').value,
'max-amount': this.$('max-amount').value,
'show-packing': this.$('show-packing').value,
'stack': this.$('stack').value,
});
var report = new Vn.ShelvesReport ({conn: this.conn});
report.setParams (
this.$('report-title').value,
this.$('max-amount').value,
this.$('show-packing').value,
this.$('stack').value,
batch
);
report.open ();
this.gui.openReport ('shelves-report', batch);
}
});
Vn.ShelvesReport = new Class
({
Extends: Vn.Report
,nItem: -1
,nColors: 5
,setParams: function (title, maxAmount, showPacking, stack, batch)
{
this.title = title;
this.maxAmount = maxAmount;
this.batch = batch;
this.showPacking = showPacking;
this.stack = stack;
}
,open: function ()
{
var query =
'SELECT id, name, width, height, depth, max_height, tray_height, '+
'first_tray_elevation, tray_density, vspacing, hspacing '+
'FROM shelf WHERE id = #shelf; '+
'CALL item_organizer (#wh, #date, #family, #filter)';
this.conn.execQuery (query, this.onQueryExec.bind (this), this.batch);
}
,onQueryExec: function (resultSet)
{
// Fetch query data
var res = resultSet.fetchResult ();
res.next ();
var maxWidth = 170;
var maxHeight = 200;
var scale = maxWidth / res.get ('width');
if (res.get ('max_height') * scale > maxHeight)
scale = maxHeight / res.get ('max_height');
var shelf = this.shelf =
{
width: res.get ('width') * scale
,height: res.get ('height') * scale
,depth: res.get ('depth') * scale
,maxHeight: res.get ('max_height') * scale
,trayHeight: res.get ('tray_height') * scale
,firstTrayElevation: res.get ('first_tray_elevation') * scale
,trayDensity: res.get ('tray_density') * scale
,vspacing: res.get ('vspacing') * scale
,hspacing: res.get ('hspacing') * scale
};
var items = [];
var remainings = [];
var res = resultSet.fetchResult ();
if (res.data.length == 0)
{
Htk.Toast.showError (_('No items found, check that all fields are correct'));
return;
}
var boxScale = scale * 10;
while (res.next ())
if (!this.maxAmount || res.get ('etiquetas') <= this.maxAmount)
{
items.push ({
id: res.get ('Id_Article')
,name: res.get ('Article')
,packing: res.get ('packing')
,amount: res.get ('etiquetas')
,boxHeight: res.get ('z') * boxScale
,boxWidth: res.get ('x') * boxScale
,boxDepth: res.get ('y') * boxScale
});
}
else
{
remainings.push ({
id: res.get ('Id_Article')
,name: res.get ('Article')
,packing: res.get ('packing')
,amount: res.get ('etiquetas')
});
}
// Intializes the allocator
alloc = new Vn.Allocator ();
alloc.items = items;
alloc.shelfFunc = this.drawShelf.bind (this);
alloc.boxFunc = this.drawBox.bind (this);
alloc.stack = this.stack;
alloc.nTrays = Math.ceil (
(shelf.height - shelf.firstTrayElevation) /
(shelf.trayHeight + shelf.trayDensity)
);
alloc.width = shelf.width - shelf.hspacing * 2;
alloc.depth = shelf.depth;
alloc.trayHeight = shelf.trayHeight - shelf.vspacing;
alloc.topTrayHeight = shelf.maxHeight - shelf.vspacing
- shelf.firstTrayElevation - (alloc.nTrays - 1) * shelf.trayHeight;
// Opens the report
if (!this.createWindow ('shelves'))
return;
// Remaining amount
if (remainings.length > 0)
{
var sheet = this.doc.createElement ('div');
sheet.className = 'sheet';
this.doc.body.appendChild (sheet);
var title = this.doc.createElement ('h1');
title.className = 'title';
title.appendChild (this.doc.createTextNode (this.title));
sheet.appendChild (title);
var subtitle = this.doc.createElement ('h2');
subtitle.className = 'subtitle';
subtitle.appendChild (this.doc.createTextNode (_('Pallets')));
sheet.appendChild (subtitle);
var ul = this.doc.createElement ('ul');
sheet.appendChild (ul);
for (var i = 0; i < remainings.length; i++)
{
var li = this.doc.createElement ('li');
ul.appendChild (li);
var span = this.doc.createElement ('span');
span.className = 'item-id';
span.appendChild (this.doc.createTextNode (remainings[i].id.toLocaleString ()));
li.appendChild (span);
var span = this.doc.createElement ('span');
span.className = 'item';
span.appendChild (this.doc.createTextNode (remainings[i].name));
li.appendChild (span);
if (this.showPacking)
span.appendChild (this.doc.createTextNode (' '+ remainings[i].packing));
var span = this.doc.createElement ('span');
span.className = 'amount';
span.appendChild (this.doc.createTextNode (remainings[i].amount));
li.appendChild (span);
}
}
// Draws the shelves
alloc.run ();
this.drawShelfEnding ();
}
,drawShelf: function (allocator, item)
{
var shelf = this.shelf;
var sheet = this.doc.createElement ('div');
sheet.className = 'sheet';
this.doc.body.appendChild (sheet);
// Draws the title
var pageNumber = this.doc.createElement ('h1');
pageNumber.className = 'page-number';
pageNumber.appendChild (this.doc.createTextNode (allocator.currentShelf + 1));
sheet.appendChild (pageNumber);
var title = this.doc.createElement ('h1');
title.className = 'title';
title.appendChild (this.doc.createTextNode (this.title));
sheet.appendChild (title);
var subtitle = this.doc.createElement ('h2');
subtitle.className = 'subtitle';
subtitle.appendChild (this.doc.createTextNode (item.id.toLocaleString ()));
sheet.appendChild (subtitle);
this.drawShelfEnding ();
this.lastSubtitle = subtitle;
// Draws the shelf
var shelfDiv = this.shelfDiv = this.doc.createElement ('div');
shelfDiv.className = 'shelf';
shelfDiv.style.width = this.mm (shelf.width);
shelfDiv.style.height = this.mm (shelf.maxHeight);
sheet.appendChild (shelfDiv);
// Draws trays
var lastTrayY = shelf.firstTrayElevation;
if (shelf.trayHeight > 0)
while (lastTrayY + shelf.trayDensity < shelf.height)
{
var tray = this.doc.createElement ('div');
tray.className = 'tray';
tray.style.width = this.mm (shelf.width);
tray.style.height = this.mm (shelf.trayDensity);
tray.style.bottom = this.mm (lastTrayY);
shelfDiv.appendChild (tray);
lastTrayY += shelf.trayHeight + shelf.trayDensity;
}
}
,drawShelfEnding: function ()
{
if (this.lastSubtitle)
this.lastSubtitle.appendChild (
this.doc.createTextNode (' - '+ this.lastItem.id.toLocaleString ()));
}
,mm: function (size)
{
return size.toFixed (2) +'mm';
}
,drawBox: function (allocator, item, amount)
{
if (item.boxWidth == 0 || item.boxHeight == 0)
return;
var shelf = this.shelf;
var x = allocator.trayX + shelf.hspacing;
var y = allocator.trayY
+ shelf.firstTrayElevation + shelf.trayDensity
+ allocator.currentTray * (shelf.trayHeight + shelf.trayDensity);
var box = this.doc.createElement ('div');
box.className = 'box';
this.shelfDiv.appendChild (box);
box.style.left = this.mm (x);
box.style.bottom = this.mm (y);
box.style.width = this.mm (item.boxWidth);
box.style.height = this.mm (item.boxHeight);
if (amount == 0)
this.nItem++;
var nColor = this.nItem % this.nColors;
Vn.Node.addClass (box, 'color'+ nColor);
if (amount == 0 || allocator.firstShelfBox)
{
var fontSize = item.boxWidth / 5.2;
if (fontSize > item.boxHeight - 1)
fontSize = item.boxHeight - 1;
var boxLabel = this.doc.createElement ('div');
boxLabel.className = 'box-label';
boxLabel.style.fontSize = this.mm (fontSize);
boxLabel.appendChild (this.doc.createTextNode (item.id.toLocaleString ()));
box.appendChild (boxLabel);
}
this.lastItem = item;
}
});
Vn.Allocator = new Class
({
addShelf: function (item)
{
this.currentShelf++;
this.firstShelfBox = true;
if (this.shelfFunc)
this.shelfFunc (this, item);
}
,addTray: function (item)
{
if (this.currentTray <= 0)
{
this.addShelf (item);
this.currentTray = this.nTrays - 1;
}
else
this.currentTray--;
this.trayX = 0;
}
,addColumn: function (item)
{
if (this.trayX + this.columnWidth + item.boxWidth > this.width
|| this.currentTray == -1)
this.addTray (item);
else
this.trayX += this.columnWidth;
this.trayY = 0;
this.columnWidth = item.boxWidth;
this.lastBoxWidth = item.boxWidth;
}
,addBox: function (item, amount)
{
var trayHeight = this.trayHeight;
if (this.currentTray == this.nTrays - 1)
trayHeight = this.topTrayHeight;
if (this.trayY + item.boxHeight > trayHeight
|| item.boxWidth > this.lastBoxWidth
|| (!this.stack && amount == 0))
this.addColumn (item);
if (this.boxFunc)
this.boxFunc (this, item, amount);
this.trayY += item.boxHeight;
if (item.boxWidth < this.lastBoxWidth)
this.lastBoxWidth = item.boxWidth;
}
,run: function ()
{
this.firstShelfBox = false;
this.currentShelf = -1;
this.currentTray = -1;
this.columnWidth = 0;
this.lastBoxWidth = 0;
this.trayX = 0;
this.trayY = 0;
this.remaining = false;
for (var i = 0; i < this.items.length; i++)
{
var item = this.items[i];
var boxIncrement = Math.floor (this.depth / item.boxDepth);
if (boxIncrement < 1)
boxIncrement = 1;
for (var amount = 0; amount < item.amount; amount += boxIncrement)
{
this.addBox (item, amount);
this.firstShelfBox = false;
}
}
return this.currentShelf + 1;
}
});

View File

@ -150,32 +150,12 @@ Vn.Catalog = new Class
if (row != -1)
title = types.get (row, 'Tipo');
}
else if (this.$('search-entry').value)
else if (this.$('search').value)
title = _('SearchResults');
Vn.Node.setText (this.$('title-text'), title);
}
,onSearch: function (event)
{
var searchTags = this.$('search-entry').value;
searchTags = searchTags != '' ? searchTags : undefined;
var batch = this.$('filter-batch');
batch.block ();
this.$('search').value = searchTags;
if (searchTags)
{
this.$('type').value = undefined;
this.$('realm').value = undefined;
}
batch.unblock ();
batch.changed ();
}
,onRightPanelClick: function (event)
{
event.stopPropagation ();
@ -247,6 +227,23 @@ Vn.Catalog = new Class
}
}
,onInfoClick: function (button, form)
{
var descNode = this.$('desc-popup');
Vn.Node.removeChilds (descNode);
var desc = this.$('items-model').get (form.row, 'description');
if (!desc)
desc = _('No info available');
descNode.appendChild (document.createTextNode (desc));
var popup = new Htk.Popup ();
popup.setChildNode (descNode);
popup.show (button.getNode ());
}
,onGridAddItemClick: function (button, form)
{
this.showAmountPopup (button.getNode (), form.row);
@ -367,6 +364,15 @@ Vn.Catalog = new Class
batch.unblock ();
batch.changed ();
}
,gridRenderer: function (res, form)
{
if (!form.get ('description'))
{
var button = res.$('info-button').getNode ();
button.style.display = 'none';
}
}
});
Vn.Filter = new Class
@ -382,8 +388,8 @@ Vn.Filter = new Class
,set: function (x)
{
x.batch = this._batch;
this._select.model = x;
this._model = x;
this._select.model = x;
}
,get: function ()
{
@ -428,21 +434,10 @@ Vn.Filter = new Class
return this._filter;
}
},
disableOperation:
{
type: Sql.FilterItem
,set: function (x)
{
this._disableFilter = x;
}
,get: function ()
{
return this._disableFilter;
}
}
}
,_columnIndex: 1
,_valueColumnIndex: 0
,_showColumnIndex: 1
,initialize: function (props)
{
@ -452,6 +447,7 @@ Vn.Filter = new Class
this._select = new Htk.Select ();
this._select.on ('mousedown', this._onClick, this);
this._select.on ('changed', this._onChange, this);
this._select.on ('ready', this._onReady, this);
this.node.appendChild (this._select.getNode ());
this._ul = document.createElement ('ul');
@ -464,31 +460,64 @@ Vn.Filter = new Class
,_onClick: function ()
{
if (this._model && this._model.status === Db.Model.Status.CLEAN)
{
this._filter.alwaysReady = true;
this._disableFilter.disabled = true;
this._model.refresh ();
this._disableFilter.disabled = false;
this._filter.alwaysReady = false;
}
}
,_onCloseClick: function (li)
{
Vn.Node.remove (li);
this._removeSelectionNode ();
this._changeValue (undefined);
}
,_removeSelectionNode: function ()
{
if (this._lastLi)
{
Vn.Node.remove (this._lastLi);
this._lastLi = null;
this._label = null;
}
}
,_onChange: function ()
{
if (this._select.value === null
|| this._select.value === undefined)
return;
if (this._lastLi)
Vn.Node.remove (this._lastLi);
this._realSetValue (this._select.value);
}
,_onReady: function ()
{
if (this._emptyLabel)
this._refreshLabel ();
}
,_changeValue: function (newValue)
{
this._batch.block ();
this.value = newValue;
this._batch.unblock ();
}
,_onTimeout: function ()
{
this._select.value = null;
}
,putValue: function (value)
{
this._onClick ();
this._realSetValue (value);
}
,_realSetValue: function (value)
{
this._removeSelectionNode ();
if (value === null || value === undefined)
return;
var li = this._lastLi = document.createElement ('li');
this._ul.appendChild (li);
@ -502,25 +531,36 @@ Vn.Filter = new Class
img.src = 'image/close.svg';
button.appendChild (img);
var label = this._select.getByIndex (this._columnIndex);
var text = document.createTextNode (label);
var text = this._label = document.createTextNode ('');
li.appendChild (text);
setTimeout (this._onTimeout.bind (this));
this._changeValue (this._select.value);
this._changeValue (value);
this._refreshLabel ();
}
,_changeValue: function (newValue)
,_refreshLabel: function ()
{
this._batch.block ();
this.value = newValue;
this._batch.unblock ();
}
if (!this._label)
return;
,_onTimeout: function ()
var row = -1;
if (this._model.ready)
row = this._model.searchByIndex (this._valueColumnIndex, this._value);
if (row != -1)
{
this._select.value = null;
var label = this._model.getByIndex (row, this._showColumnIndex);
this._label.nodeValue = label;
this._emptyLabel = false;
}
else
{
this._emptyLabel = true;
this._label.nodeValue = _('Loading...');
}
}
});

View File

@ -33,28 +33,9 @@
/* Topbar */
.action-bar > div > .search
.catalog-actions > .htk-search-entry
{
margin-top: .8em;
background-color: white;
height: 2.3em;
}
.search > input
{
margin: 0;
border: none;
width: 8em;
box-shadow: none;
}
.search > input:focus
{
background-color: initial;
}
.search > img
{
margin: 0;
margin-left: .4em;
vertical-align: middle;
}
/* Right panel */
@ -177,6 +158,14 @@ button.basket:hover
background-color: rgba(1, 1, 1, .1);
}
/* Item description */
.desc-popup
{
padding: 1em;
max-width: 15em;
}
/* Lots popup*/
div.amount
@ -317,6 +306,10 @@ td.third-category
bottom: .5em;
right: .5em;
}
.item-box > .info-button
{
float: right;
}
/* Transitions */
@ -327,18 +320,18 @@ td.third-category
/* Mobile */
.catalog-actions button.menu
.catalog-actions > button.menu
{
display: none;
}
.catalog-actions button.menu > img
.catalog-actions > button.menu > img
{
height: 1.8em;
}
@media (max-width: 950px)
{
.catalog-actions button.menu
.catalog-actions > button.menu
{
display: block;
}

View File

@ -10,16 +10,16 @@
</vn-group>
<vn-group>
<sql-filter type="AND" id="filter">
<sql-filter-item type="EQUAL" primary="false" id="op-realm">
<sql-field name="reino_id" target="t"/>
<sql-value param="realm"/>
</sql-filter-item>
<sql-filter-item type="LIKE" id="op-name">
<sql-field name="Article"/>
<sql-search-tags param="search"/>
</sql-filter-item>
<sql-filter-item type="EQUAL" id="op-realm">
<sql-field name="reino_id" target="t"/>
<sql-value param="realm"/>
</sql-filter-item>
<sql-filter-item type="EQUAL" id="op-type">
<sql-field name="tipo_id"/>
<sql-field name="tipo_id" target="a"/>
<sql-value param="type"/>
</sql-filter-item>
<sql-filter-item type="EQUAL" id="op-color">
@ -39,11 +39,6 @@
<sql-value param="producer"/>
</sql-filter-item>
</sql-filter>
<sql-batch property="batch" id="filter-batch">
<custom>
<item name="filter" object="filter"/>
</custom>
</sql-batch>
</vn-group>
<vn-group>
<vn-hash-param key="realm" param="realm"/>
@ -55,26 +50,32 @@
GROUP BY warehouse_id
</custom>
</db-query>
<db-model result-index="2" id="items-model" batch="filter-batch">
<db-model result-index="2" id="items-model">
<custom>
CREATE TEMPORARY TABLE tmp.bionic_calc
(INDEX (item_id))
ENGINE=MEMORY
SELECT Id_Article item_id FROM vn2008.Articles
SELECT a.Id_Article item_id FROM vn2008.Articles a
JOIN vn2008.Tipos t ON t.tipo_id = a.tipo_id
WHERE #filter;
CALL bionic_calc ();
SELECT a.Id_Article item_id, a.description, t.available, t.price,
SELECT a.Id_Article item_id, a.description, b.available, b.price,
p.name producer, a.Foto, a.Article, a.Categoria, a.Medida,
a.Tallos, i.name color, o.Abreviatura, o.Origen
FROM tmp.bionic_item t
JOIN vn2008.Articles a ON a.Id_Article = t.item_id
a.Tallos, c.str color, o.str origin
FROM tmp.bionic_item b
JOIN vn2008.Articles a ON a.Id_Article = b.item_id
LEFT JOIN vn2008.producer p ON p.producer_id = a.producer_id
LEFT JOIN vn2008.Tintas i ON i.Id_Tinta = a.Color
LEFT JOIN vn2008.Origen o ON a.id_origen = o.id
WHERE t.available > 0
LEFT JOIN vn_locale.color_view c ON c.color_id = a.Color
LEFT JOIN vn_locale.origin_view o ON o.origin_id = a.id_origen
WHERE b.available > 0
ORDER BY a.Article, a.Medida
LIMIT 400;
</custom>
<sql-batch property="batch" id="filter-batch">
<custom>
<item name="filter" object="filter"/>
</custom>
</sql-batch>
</db-model>
<db-model id="item-lots" result-index="1" on-status-changed-after="onStatusChange">
<custom>
@ -92,10 +93,8 @@
<h1 id="title-text"><t>Catalog</t></h1>
</div>
<div id="actions" class="catalog-actions">
<div class="search">
<img src="image/search.svg" alt="_Search" class="icon"/>
<input type="text" id="search-entry" on-change="onSearch"/>
</div>
<htk-search-entry
param="search"/>
<htk-button
image="image/dark/view.svg"
tip="_Switch view"
@ -118,7 +117,11 @@
</div>
<div id="list-view" class="list-view">
<div class="box">
<htk-grid id="items-grid" class="items" empty-message="_SelectSubtype" show-header="false">
<htk-grid
id="items-grid"
class="items"
empty-message="_Select filter from right menu"
show-header="false">
<htk-column-image
title="*"
class="icon"
@ -157,7 +160,12 @@
</p>
</div>
</div>
<htk-repeater id="grid-view" class="grid-view" empty-message="_SelectSubtype" form-id="item">
<htk-repeater
id="grid-view"
class="grid-view"
empty-message="_Select filter from right menu"
form-id="item"
renderer="gridRenderer">
<custom>
<div class="box item-box">
<div class="image">
@ -169,6 +177,14 @@
show-full="true"
full-dir="900x900"/>
</div>
<htk-button
form="item"
column="id"
tip="_More info"
image="image/info.svg"
on-click="onInfoClick"
id="info-button"
class="info-button"/>
<h2>
<htk-text form="item" column="Article"/>
</h2>
@ -181,7 +197,7 @@
<htk-text form="item" column="color"/>
</p>
<p>
<htk-text form="item" column="Origen"/>
<htk-text form="item" column="origin"/>
<htk-text form="item" column="Tallos" format="%.0d Units"/>
</p>
<div class="aval-price">
@ -241,55 +257,73 @@
property="model"
on-status-changed="onTypeChange">
<custom>
SELECT id, reino, color FROM vn2008.reinos
WHERE display != FALSE ORDER BY reino
SELECT r.id, l.str name, r.color
FROM vn2008.reinos r
LEFT JOIN vn_locale.realm_view l ON l.realm_id = r.id
WHERE r.display != FALSE
ORDER BY name
</custom>
</db-model>
</vn-filter>
<vn-filter
placeholder="_Family"
param="type"
filter="filter"
disable-operation="op-type">
param="type">
<db-model
id="types-model"
property="model"
conn="conn"
auto-load="false"
result-index="1"
on-status-changed="refreshTitle">
<custom>
CALL item_available ();
SELECT DISTINCT t.tipo_id, t.Tipo type
SELECT DISTINCT t.tipo_id, l.str name
FROM vn2008.Tipos t
JOIN vn2008.Articles a ON a.tipo_id = t.tipo_id
LEFT JOIN vn_locale.family_view l ON l.family_id = t.tipo_id
JOIN tmp.item_available i ON i.item_id = a.Id_Article
WHERE #filter
ORDER BY t.Tipo
ORDER BY name
</custom>
</db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<sql-filter-item type="EQUAL" id="op-realm">
<sql-field name="reino_id" target="t"/>
<sql-value param="realm"/>
</sql-filter-item>
<pointer object="op-name"/>
<pointer object="op-color"/>
<pointer object="op-origin"/>
<pointer object="op-category"/>
<pointer object="op-producer"/>
</sql-filter>
</vn-filter>
<vn-filter
placeholder="_Color"
param="color"
filter="filter"
disable-operation="op-color">
param="color">
<db-model property="model" auto-load="false" result-index="1">
<custom>
CALL item_available ();
SELECT DISTINCT c.Id_Tinta, c.name
SELECT DISTINCT c.Id_Tinta, l.str name
FROM vn2008.Tintas c
JOIN vn2008.Articles a ON a.Color = c.Id_Tinta
LEFT JOIN vn_locale.color_view l ON l.color_id = c.Id_Tinta
JOIN tmp.item_available i ON i.item_id = a.Id_Article
WHERE #filter
ORDER BY c.name
ORDER BY name
</custom>
</db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<pointer object="op-name"/>
<pointer object="op-type"/>
<pointer object="op-origin"/>
<pointer object="op-category"/>
<pointer object="op-producer"/>
</sql-filter>
</vn-filter>
<vn-filter
placeholder="_Producer"
param="producer"
filter="filter"
disable-operation="op-producer">
param="producer">
<db-model property="model" auto-load="false" result-index="1">
<custom>
CALL item_available ();
@ -298,32 +332,43 @@
JOIN vn2008.Articles a ON a.producer_id = p.producer_id
JOIN tmp.item_available i ON i.item_id = a.Id_Article
WHERE #filter
ORDER BY p.name
ORDER BY name
</custom>
</db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<pointer object="op-name"/>
<pointer object="op-type"/>
<pointer object="op-origin"/>
<pointer object="op-color"/>
<pointer object="op-category"/>
</sql-filter>
</vn-filter>
<vn-filter
placeholder="_Origin"
param="origin"
filter="filter"
disable-operation="op-origin">
param="origin">
<db-model property="model" auto-load="false" result-index="1">
<custom>
CALL item_available ();
SELECT DISTINCT o.id, o.Origen, o.Abreviatura
SELECT DISTINCT o.id, l.str name, o.Abreviatura
FROM vn2008.Origen o
JOIN vn2008.Articles a ON a.id_origen = o.id
LEFT JOIN vn_locale.origin_view l ON l.origin_id = o.id
JOIN tmp.item_available i ON i.item_id = a.Id_Article
WHERE #filter
ORDER BY o.Origen
ORDER BY name
</custom>
</db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<pointer object="op-name"/>
<pointer object="op-type"/>
<pointer object="op-color"/>
<pointer object="op-category"/>
<pointer object="op-producer"/>
</sql-filter>
</vn-filter>
<vn-filter
placeholder="_Category"
param="category"
filter="filter"
disable-operation="op-category">
param="category">
<db-model property="model" auto-load="false" result-index="1">
<custom>
CALL item_available ();
@ -334,6 +379,13 @@
ORDER BY a.Categoria
</custom>
</db-model>
<sql-filter property="filter" always-ready="true" type="AND">
<pointer object="op-name"/>
<pointer object="op-type"/>
<pointer object="op-color"/>
<pointer object="op-origin"/>
<pointer object="op-producer"/>
</sql-filter>
</vn-filter>
<button class="remove-filters thin" on-click="onRemoveFiltersClick">
<t>Remove filters</t>
@ -375,6 +427,7 @@
</htk-repeater>
-->
</div>
<div id="desc-popup" class="desc-popup"/>
<div id="lots-popup" class="lots-popup">
<htk-grid class="lots-grid" model="item-lots" show-header="false">
<htk-column-text title="_Store" column="warehouse"/>

View File

@ -6,11 +6,13 @@
<div class="box">
<div>
<htk-grid show-header="false">
<db-model id="tickets">
<db-model property="model" id="tickets">
<custom>
SELECT invoice_id, serial_num, issued, amount
FROM invoice_view
ORDER BY issued DESC
LIMIT 100
</custom>
</db-model>
<htk-column-text title="_Serial" column="serial_num"/>
<htk-column-date title="_Date" column="issued" format="_%e %b %Y"/>

View File

@ -3,19 +3,11 @@ Vn.Ticket = new Class
({
Extends: Vn.Form
,activate: function ()
,onPrintClick: function (event)
{
this.$('print').addEventListener ('click', this.printClicked.bind (this));
this.$('subtotal').renderer = this.subtotalRenderer.bind (this);
this.$('ticket-subtotal').func = this.subtotal;
}
,printClicked: function (event)
{
var report = window.open ('', 'report',
'resizable=yes,height=600,width=750,scrollbars=yes,menubar=no');
report.document.body.innerHTML = this.$('report').innerHTML;
report.print ();
var batch = new Sql.Batch ();
batch.addValue ('ticket', this.$('ticket-id').value);
this.gui.openReport ('delivery-note', batch);
}
,subtotalRenderer: function (column, form)

View File

@ -1,8 +1,7 @@
<vn>
<vn-group>
<vn-hash-param key="ticket">
<vn-param id="ticket-id"/>
</vn-hash-param>
<vn-hash-param key="ticket" param="ticket-id"/>
<db-form id="ticket">
<db-model property="model" id="ticket-data">
<custom>
@ -26,10 +25,11 @@
<h1><t>OrderDetail</t></h1>
</div>
<div id="actions" class="action-bar">
<button id="print">
<img src="image/dark/print.svg" alt=""/>
<t>Print</t>
</button>
<htk-button
image="image/dark/print.svg"
tip="_Print delivery note"
on-click="onPrintClick"
showText="true"/>
</div>
<div id="form" class="ticket">
<div class="box">
@ -74,7 +74,7 @@
</td>
<td>
<htk-text format="%.2d€">
<db-calc-sum id="ticket-subtotal" model="movements"/>
<db-calc-sum func="subtotal" model="movements"/>
</htk-text>
</td>
</tr>
@ -115,7 +115,7 @@
<htk-column-text title="_Origin" column="Abreviatura"/>
<htk-column-spin title="_Price" column="price" unit="€" digits="2"/>
<htk-column-spin title="_Desc" column="discount" unit="%"/>
<htk-column-spin title="_Subtotal" unit="€" digits="2" id="subtotal"/>
<htk-column-spin title="_Subtotal" unit="€" digits="2" renderer="subtotalRenderer"/>
</htk-grid>
</div>
</div>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<!-- The icon can be used freely in both personal and commercial projects with no attribution required, but always appreciated.
You may NOT sub-license, resell, rent, redistribute or otherwise transfer the icon without express written permission from iconmonstr.com -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
@ -9,115 +10,41 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg7384"
version="1.1"
inkscape:version="0.48.5 r10040"
x="0px"
y="0px"
width="16"
height="16"
sodipodi:docname="info.svg"
width="16">
<metadata
id="metadata90">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
inkscape:cy="7.0274833"
inkscape:current-layer="layer9"
inkscape:window-width="1920"
pagecolor="#555753"
showborder="false"
showguides="true"
inkscape:snap-nodes="true"
objecttolerance="10"
showgrid="false"
inkscape:object-nodes="true"
inkscape:pageshadow="2"
inkscape:guide-bbox="true"
inkscape:window-x="1920"
inkscape:snap-bbox="true"
viewBox="0 0 16 16"
enable-background="new 0 0 512 512"
xml:space="preserve"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="info.svg"><metadata
id="metadata9"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
id="namedview88"
inkscape:window-maximized="1"
inkscape:snap-global="true"
inkscape:window-y="27"
gridtolerance="10"
inkscape:zoom="45.078231"
inkscape:window-height="1014"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:cx="3.8262706"
inkscape:bbox-paths="false"
inkscape:snap-grids="true"
inkscape:pageopacity="1"
inkscape:snap-to-guides="true">
<inkscape:grid
visible="true"
spacingx="1px"
type="xygrid"
spacingy="1px"
id="grid4866"
empspacing="2"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<defs
id="defs7386" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer9"
inkscape:label="status"
style="display:inline">
<path
d="m 287.53551,259.96102 c -0.32661,0 -0.66541,0.12985 -0.91815,0.38255 l -5.20278,5.20277 c -0.50544,0.50543 -0.50544,1.33087 0,1.83629 l 5.20278,5.20279 c 0.50544,0.50541 1.33084,0.50541 1.83629,0 l 5.20277,-5.20279 c 0.50544,-0.50542 0.50544,-1.33086 0,-1.83629 l -5.20277,-5.20277 c -0.25273,-0.2527 -0.59154,-0.38255 -0.91814,-0.38255 z m -0.15302,2.42286 c 1.34042,-0.075 2.52629,0.95493 2.60138,2.29534 -8e-5,1.14368 -0.30825,1.56841 -1.30069,2.32085 -0.15583,0.11723 -0.26573,0.20453 -0.30604,0.25504 -0.0403,0.0507 -0.0254,0.0271 -0.0254,0.0254 0.006,0.43119 -0.38491,0.81613 -0.81612,0.81613 -0.43122,0 -0.82184,-0.38494 -0.81612,-0.81613 0,-0.41 0.183,-0.76994 0.38255,-1.02014 0.19955,-0.25025 0.40096,-0.42144 0.58659,-0.56109 0.16652,-0.13104 0.37609,-0.31383 0.56108,-0.53558 0.0763,-0.0915 0.10528,-0.25108 0.10202,-0.35706 l 0,-0.0255 c -0.0258,-0.45966 -0.40746,-0.7909 -0.86714,-0.76511 -0.45966,0.0258 -0.79089,0.35644 -0.7651,0.81613 l -1.63226,0 c -0.075,-1.34043 0.95494,-2.37322 2.29535,-2.44838 z m 0.15302,6.52899 c 0.45072,0 0.81612,0.36539 0.81612,0.81611 0,0.45073 -0.3654,0.81612 -0.81612,0.81612 -0.45072,0 -0.81612,-0.36539 -0.81612,-0.81612 0,-0.45072 0.3654,-0.81611 0.81612,-0.81611 z"
id="path19592"
style="color:#bebebe;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
</g>
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer10"
inkscape:label="devices" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer11"
inkscape:label="apps" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer12"
inkscape:label="actions" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer13"
inkscape:label="places" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer14"
inkscape:label="mimetypes" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer15"
inkscape:label="emblems"
style="display:inline" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="g4953"
inkscape:label="categories"
style="display:inline" />
</svg>
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1016"
id="namedview5"
showgrid="false"
inkscape:zoom="51.6875"
inkscape:cx="7.2631221"
inkscape:cy="7.9613059"
inkscape:window-x="1920"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" /><path
id="info-2-icon"
d="m 7.999935,2.762144 c 2.89471,0 5.237934,2.342561 5.237934,5.23783 0,2.894749 -2.342691,5.237882 -5.237934,5.237882 -2.89471,0 -5.237804,-2.342626 -5.237804,-5.237882 0,-2.894723 2.342626,-5.23783 5.237804,-5.23783 m 0,-1.262144 C 4.410141,1.5 1.5,4.410115 1.5,7.999974 1.5,11.589846 4.410141,14.5 7.999935,14.5 11.589794,14.5 14.5,11.589846 14.5,7.999974 14.5,4.410115 11.589833,1.5 7.999935,1.5 l 0,0 z m 0.941044,10.020335 -1.818921,0 0,-4.321798 1.818921,0 0,4.321798 z M 8.031551,6.304566 c -0.552877,0 -1.001156,-0.448253 -1.001156,-1.001195 0,-0.552877 0.448253,-1.001169 1.001156,-1.001169 0.552942,0 1.00113,0.448253 1.00113,1.001169 0,0.552942 -0.448188,1.001195 -1.00113,1.001195 z"
inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1" /></svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<!-- The icon can be used freely in both personal and commercial projects with no attribution required, but always appreciated.
You may NOT sub-license, resell, rent, redistribute or otherwise transfer the icon without express written permission from iconmonstr.com -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
@ -9,115 +10,41 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg7384"
version="1.1"
inkscape:version="0.48.5 r10040"
x="0px"
y="0px"
width="16"
height="16"
sodipodi:docname="info.svg"
width="16">
<metadata
id="metadata90">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
inkscape:cy="2.2028437"
inkscape:current-layer="layer9"
inkscape:window-width="1920"
pagecolor="#555753"
showborder="false"
showguides="true"
inkscape:snap-nodes="true"
objecttolerance="10"
showgrid="false"
inkscape:object-nodes="true"
inkscape:pageshadow="2"
inkscape:guide-bbox="true"
inkscape:window-x="1920"
inkscape:snap-bbox="true"
viewBox="0 0 16 16"
enable-background="new 0 0 512 512"
xml:space="preserve"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="info.svg"><metadata
id="metadata9"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
id="namedview88"
inkscape:window-maximized="1"
inkscape:snap-global="true"
inkscape:window-y="27"
gridtolerance="10"
inkscape:zoom="7.9687808"
inkscape:window-height="1014"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:cx="5.435957"
inkscape:bbox-paths="false"
inkscape:snap-grids="true"
inkscape:pageopacity="1"
inkscape:snap-to-guides="true">
<inkscape:grid
visible="true"
spacingx="1px"
type="xygrid"
spacingy="1px"
id="grid4866"
empspacing="2"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<defs
id="defs7386" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer9"
inkscape:label="status"
style="display:inline">
<path
d="m 287.53551,259.96102 c -0.32661,0 -0.66541,0.12985 -0.91815,0.38255 l -5.20278,5.20277 c -0.50544,0.50543 -0.50544,1.33087 0,1.83629 l 5.20278,5.20279 c 0.50544,0.50541 1.33084,0.50541 1.83629,0 l 5.20277,-5.20279 c 0.50544,-0.50542 0.50544,-1.33086 0,-1.83629 l -5.20277,-5.20277 c -0.25273,-0.2527 -0.59154,-0.38255 -0.91814,-0.38255 z m -0.15302,2.42286 c 1.34042,-0.075 2.52629,0.95493 2.60138,2.29534 -8e-5,1.14368 -0.30825,1.56841 -1.30069,2.32085 -0.15583,0.11723 -0.26573,0.20453 -0.30604,0.25504 -0.0403,0.0507 -0.0254,0.0271 -0.0254,0.0254 0.006,0.43119 -0.38491,0.81613 -0.81612,0.81613 -0.43122,0 -0.82184,-0.38494 -0.81612,-0.81613 0,-0.41 0.183,-0.76994 0.38255,-1.02014 0.19955,-0.25025 0.40096,-0.42144 0.58659,-0.56109 0.16652,-0.13104 0.37609,-0.31383 0.56108,-0.53558 0.0763,-0.0915 0.10528,-0.25108 0.10202,-0.35706 l 0,-0.0255 c -0.0258,-0.45966 -0.40746,-0.7909 -0.86714,-0.76511 -0.45966,0.0258 -0.79089,0.35644 -0.7651,0.81613 l -1.63226,0 c -0.075,-1.34043 0.95494,-2.37322 2.29535,-2.44838 z m 0.15302,6.52899 c 0.45072,0 0.81612,0.36539 0.81612,0.81611 0,0.45073 -0.3654,0.81612 -0.81612,0.81612 -0.45072,0 -0.81612,-0.36539 -0.81612,-0.81612 0,-0.45072 0.3654,-0.81611 0.81612,-0.81611 z"
id="path19592"
style="color:#bebebe;fill:#748cc9;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
</g>
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer10"
inkscape:label="devices" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer11"
inkscape:label="apps" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer12"
inkscape:label="actions" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer13"
inkscape:label="places" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer14"
inkscape:label="mimetypes" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer15"
inkscape:label="emblems"
style="display:inline" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="g4953"
inkscape:label="categories"
style="display:inline" />
</svg>
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1016"
id="namedview5"
showgrid="false"
inkscape:zoom="51.6875"
inkscape:cx="7.2631221"
inkscape:cy="7.9613059"
inkscape:window-x="1920"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" /><path
id="info-2-icon"
d="m 7.999935,2.762144 c 2.89471,0 5.237934,2.342561 5.237934,5.23783 0,2.894749 -2.342691,5.237882 -5.237934,5.237882 -2.89471,0 -5.237804,-2.342626 -5.237804,-5.237882 0,-2.894723 2.342626,-5.23783 5.237804,-5.23783 m 0,-1.262144 C 4.410141,1.5 1.5,4.410115 1.5,7.999974 1.5,11.589846 4.410141,14.5 7.999935,14.5 11.589794,14.5 14.5,11.589846 14.5,7.999974 14.5,4.410115 11.589833,1.5 7.999935,1.5 l 0,0 z m 0.941044,10.020335 -1.818921,0 0,-4.321798 1.818921,0 0,4.321798 z M 8.031551,6.304566 c -0.552877,0 -1.001156,-0.448253 -1.001156,-1.001195 0,-0.552877 0.448253,-1.001169 1.001156,-1.001169 0.552942,0 1.00113,0.448253 1.00113,1.001169 0,0.552942 -0.448188,1.001195 -1.00113,1.001195 z"
inkscape:connector-curvature="0"
style="fill:#666666;fill-opacity:1" /></svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

123
web/image/unknown.svg Normal file
View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg7384"
version="1.1"
inkscape:version="0.48.5 r10040"
height="16"
sodipodi:docname="info.svg"
width="16">
<metadata
id="metadata90">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
inkscape:cy="2.2028437"
inkscape:current-layer="layer9"
inkscape:window-width="1920"
pagecolor="#555753"
showborder="false"
showguides="true"
inkscape:snap-nodes="true"
objecttolerance="10"
showgrid="false"
inkscape:object-nodes="true"
inkscape:pageshadow="2"
inkscape:guide-bbox="true"
inkscape:window-x="1920"
inkscape:snap-bbox="true"
bordercolor="#666666"
id="namedview88"
inkscape:window-maximized="1"
inkscape:snap-global="true"
inkscape:window-y="27"
gridtolerance="10"
inkscape:zoom="7.9687808"
inkscape:window-height="1014"
borderopacity="1"
guidetolerance="10"
inkscape:cx="5.435957"
inkscape:bbox-paths="false"
inkscape:snap-grids="true"
inkscape:pageopacity="1"
inkscape:snap-to-guides="true">
<inkscape:grid
visible="true"
spacingx="1px"
type="xygrid"
spacingy="1px"
id="grid4866"
empspacing="2"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<title
id="title9167">Gnome Symbolic Icon Theme</title>
<defs
id="defs7386" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer9"
inkscape:label="status"
style="display:inline">
<path
d="m 287.53551,259.96102 c -0.32661,0 -0.66541,0.12985 -0.91815,0.38255 l -5.20278,5.20277 c -0.50544,0.50543 -0.50544,1.33087 0,1.83629 l 5.20278,5.20279 c 0.50544,0.50541 1.33084,0.50541 1.83629,0 l 5.20277,-5.20279 c 0.50544,-0.50542 0.50544,-1.33086 0,-1.83629 l -5.20277,-5.20277 c -0.25273,-0.2527 -0.59154,-0.38255 -0.91814,-0.38255 z m -0.15302,2.42286 c 1.34042,-0.075 2.52629,0.95493 2.60138,2.29534 -8e-5,1.14368 -0.30825,1.56841 -1.30069,2.32085 -0.15583,0.11723 -0.26573,0.20453 -0.30604,0.25504 -0.0403,0.0507 -0.0254,0.0271 -0.0254,0.0254 0.006,0.43119 -0.38491,0.81613 -0.81612,0.81613 -0.43122,0 -0.82184,-0.38494 -0.81612,-0.81613 0,-0.41 0.183,-0.76994 0.38255,-1.02014 0.19955,-0.25025 0.40096,-0.42144 0.58659,-0.56109 0.16652,-0.13104 0.37609,-0.31383 0.56108,-0.53558 0.0763,-0.0915 0.10528,-0.25108 0.10202,-0.35706 l 0,-0.0255 c -0.0258,-0.45966 -0.40746,-0.7909 -0.86714,-0.76511 -0.45966,0.0258 -0.79089,0.35644 -0.7651,0.81613 l -1.63226,0 c -0.075,-1.34043 0.95494,-2.37322 2.29535,-2.44838 z m 0.15302,6.52899 c 0.45072,0 0.81612,0.36539 0.81612,0.81611 0,0.45073 -0.3654,0.81612 -0.81612,0.81612 -0.45072,0 -0.81612,-0.36539 -0.81612,-0.81612 0,-0.45072 0.3654,-0.81611 0.81612,-0.81611 z"
id="path19592"
style="color:#bebebe;fill:#748cc9;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
</g>
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer10"
inkscape:label="devices" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer11"
inkscape:label="apps" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer12"
inkscape:label="actions" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer13"
inkscape:label="places" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer14"
inkscape:label="mimetypes" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="layer15"
inkscape:label="emblems"
style="display:inline" />
<g
transform="translate(-281.0002,-257)"
inkscape:groupmode="layer"
id="g4953"
inkscape:label="categories"
style="display:inline" />
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -61,7 +61,7 @@ Vn.App = new Class
error.fileName = file;
error.lineNumber = line;
Htk.Toast.showError (_('InternalError'));
Htk.Toast.showError (_('There was an internal error'));
this.notifyError (error);
}

View File

@ -34,6 +34,7 @@ Vn.Form = new Class
var builder = new Vn.Builder ();
builder.signalData = this;
builder.add ('conn', this.conn);
builder.loadXml ('forms/'+ this.formInfo.path +'/ui.xml');
var res = this.builder = builder.load ();

View File

@ -65,14 +65,13 @@
font-weight: normal;
font-size: 1.4em;
padding: .7em .6em;
padding-right: 0;
margin: 0;
}
.vn-gui .top-bar > .loader
.vn-gui .top-bar > .htk-spinner
{
float: right;
margin: 5% 1em;
visibility: hidden;
height: 90%;
float: left;
margin: 1.05em .8em;
}
.vn-gui .exit
{
@ -110,7 +109,6 @@
{
float: left;
padding: 0;
margin: 1.3em .5em;
}
.vn-gui .action-bar button
{

View File

@ -253,7 +253,7 @@ Vn.Gui = new Class
this.loadingCount++;
if (this.loadingCount == 1)
this.$('loader').style.visibility = 'visible';
this.$('loader').start ();
}
,loaderPop: function ()
@ -264,7 +264,7 @@ Vn.Gui = new Class
this.loadingCount--;
if (this.loadingCount == 0)
this.$('loader').style.visibility = 'hidden';
this.$('loader').stop ();
}
,newVersion: function (error)

View File

@ -35,10 +35,8 @@
<img src="image/dark/exit.svg" alt="_Exit"/>
</button>
<div id="action-bar" class="action-bar"/>
<div id="loader" class="loader">
<htk-loader/>
</div>
<div id="title" class="title"/>
<htk-spinner id="loader" class="loader dark"/>
</div>
<div class="content">
<div id="form-holder" class="form-holder"/>

View File

@ -28,33 +28,7 @@ Vn.Report = new Class
,open: function (batch)
{
this.batch = batch;
this.createWindow (this._onWindowLoad.bind (this));
}
,_onWindowLoad: function ()
{
this.doc = this.window.document
var path = this.info.path;
this.includeCss ('reports/'+ path +'/style.css');
var printButton = this.doc.createElement ('button');
printButton.className = 'print-button';
printButton.appendChild (this.doc.createTextNode (_('Print')));
printButton.addEventListener ('click', this.print.bind (this));
this.doc.body.appendChild (printButton);
var builder = new Vn.Builder ();
builder.signalData = this;
builder.add ('batch', this.batch);
builder.add ('conn', this.conn);
builder.loadXml ('reports/'+ path +'/ui.xml');
var res = this.builderResult = builder.load ();
res.link ();
this.doc.body.appendChild (res.$('report'));
this.createWindow ();
}
,print: function ()
@ -78,21 +52,58 @@ Vn.Report = new Class
head.appendChild (link);
}
,createWindow: function (callback)
,createWindow: function ()
{
var reportWindow = window.open ('js/hedera/report.html', '_blank'/*this.info.path*/,
'resizable=yes,height=900,width=900,scrollbars=yes,menubar=false');
var reportWindow = window.open (
'js/hedera/report.html', '_blank',
'height=950, width=950, resizable=yes, fullscreen=no,'+
'titlebar=no, menubar=no, toolbar=no, location=no, scrollbars=yes'
);
if (!reportWindow)
{
Htk.Toast.showError (
_('Please unlock popups and try again'));
return null;
if (callback)
callback (null);
return false;
}
reportWindow.addEventListener ('load', callback);
reportWindow.addEventListener ('load',
this._onWindowLoad.bind (this));
this.window = reportWindow;
return reportWindow;
return true;
}
,_onWindowLoad: function ()
{
this.doc = this.window.document
this.includeCss ('reports/'+ this.info.path +'/style.css');
var printButton = this.doc.createElement ('button');
printButton.className = 'print-button';
printButton.appendChild (this.doc.createTextNode (_('Print')));
printButton.addEventListener ('click', this.print.bind (this));
this.doc.body.appendChild (printButton);
this.onWindowCreate ();
}
,onWindowCreate: function ()
{
var builder = new Vn.Builder ();
builder.signalData = this;
builder.add ('batch', this.batch);
builder.add ('conn', this.conn);
builder.loadXml ('reports/'+ this.info.path +'/ui.xml');
var res = this.builderResult = builder.load ();
res.link ();
this.doc.body.appendChild (res.$('report'));
}
});

View File

@ -56,7 +56,7 @@ Htk.Field = new Class
},
form:
{
type: Vn.Object // Db.Iterator
type: Db.Iterator
,set: function (x)
{
this._form = x;

View File

@ -0,0 +1,52 @@
Htk.SearchEntry = new Class
({
Extends: Htk.Field
,Tag: 'htk-search-entry'
,initialize: function (props)
{
var div = this.createElement ('div');
div.className = 'htk-search-entry';
var img = document.createElement ('img');
img.alt = _('Search');
img.src = 'image/search.svg';
div.appendChild (img);
var input = document.createElement ('input');
input.className = 'entry';
input.type = 'text';
input.placeholder = _('Search');
input.addEventListener ('change', this._onChange.bind (this));
div.appendChild (input);
this._input = input;
this.parent (props);
}
,_onChange: function (event)
{
var newValue;
if (this._input.value === '')
newValue = undefined;
else
newValue = this._input.value;
this.valueChanged (newValue);
}
,putValue: function (value)
{
if (!value)
this._input.value = '';
else
this._input.value = value;
}
,setEditable: function (editable)
{
this.node.readOnly = !editable;
}
});

View File

@ -13,8 +13,8 @@ Htk.Select = new Class
type: Db.Model
,set: function (x)
{
this.link ({_model: x}, {'status-changed': this.onModelChange});
this.onModelChange ();
this.link ({_model: x}, {'status-changed': this._onModelChange});
this._onModelChange ();
}
,get: function ()
{
@ -64,7 +64,7 @@ Htk.Select = new Class
type: Boolean
,get: function ()
{
return this._ready;
return this._model && this._model.ready;
}
},
/**
@ -196,7 +196,7 @@ Htk.Select = new Class
this._placeholderNode = option;
}
,onModelChange: function ()
,_onModelChange: function ()
{
var placeholder = null;
var model = this._model;

View File

@ -6,6 +6,9 @@ Htk.Grid = new Class
,Child: 'model'
,Properties:
{
/**
* The source data model.
**/
model:
{
type: Db.Model
@ -31,11 +34,17 @@ Htk.Grid = new Class
return this._model;
}
},
/**
* Message that should be displayed when source model is not ready.
**/
emptyMessage:
{
type: String
,value: _('NoData')
},
/**
* Wether to display the header with column titles.
**/
showHeader:
{
type: Boolean
@ -200,7 +209,7 @@ Htk.Grid = new Class
break;
}
case Db.Model.Status.LOADING:
this.showMessage (_('Loading'), 'loader-black.gif');
this.showMessage (_('Loading'), null);
break;
case Db.Model.Status.CLEAN:
this.showMessage (this.emptyMessage, 'refresh.svg');
@ -232,10 +241,19 @@ Htk.Grid = new Class
td.colSpan = this.columns.length;
tr.appendChild (td);
if (src)
{
var img = document.createElement ('img');
img.alt = '';
img.src = 'image/'+ src;
td.appendChild (img);
}
else
{
var spinner = new Htk.Spinner ();
spinner.start ();
td.appendChild (spinner.getNode ());
}
var message = document.createTextNode (message);
td.appendChild (message);

View File

@ -1,74 +0,0 @@
.htk-loader
{
font-size: 10px;
margin: 50px auto;
text-indent: -9999em;
width: 11em;
height: 11em;
border-radius: 50%;
background: #ffffff;
background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
position: relative;
-webkit-animation: load3 1.4s infinite linear;
animation: load3 1.4s infinite linear;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
}
.htk-loader:before
{
width: 50%;
height: 50%;
background: #ffffff;
border-radius: 100% 0 0 0;
position: absolute;
top: 0;
left: 0;
content: '';
}
.htk-loader:after
{
background: #0dc5c1;
width: 75%;
height: 75%;
border-radius: 50%;
content: '';
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
@-webkit-keyframes load3
{
0%
{
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100%
{
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes load3
{
0%
{
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100%
{
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}

View File

@ -1,13 +0,0 @@
Htk.Loader = new Class
({
Extends: Htk.Widget
,Tag: 'htk-loader'
,initialize: function (props)
{
var loader = this.createElement ('div');
loader.className = 'htk-loader';
this.parent (props);
}
});

View File

@ -9,7 +9,7 @@ Vn.includeLib ('htk',
,'toast'
,'repeater'
,'grid'
,'loader'
,'spinner'
,'full-image'
,'image-editor'
,'assistant'
@ -30,6 +30,7 @@ Vn.includeLib ('htk',
,'field/image'
,'field/button'
,'field/table'
,'field/search-entry'
,'column'
,'column/button'
,'column/link'

View File

@ -5,6 +5,9 @@ Htk.Repeater = new Class
,Child: 'model'
,Properties:
{
/**
* The source data model.
**/
model:
{
type: Db.Model
@ -25,6 +28,9 @@ Htk.Repeater = new Class
this._model;
}
}
/**
* The identifier for internal iterator.
**/
,formId:
{
type: String
@ -37,6 +43,10 @@ Htk.Repeater = new Class
this._formId;
}
}
/**
* {Function (Vn.BuilderResult, Db.Form)} Function to call after every
* box rendering.
**/
,renderer:
{
type: Function
@ -49,6 +59,9 @@ Htk.Repeater = new Class
this._renderer;
}
}
/**
* Message that should be displayed when source model is not ready.
**/
,emptyMessage:
{
type: String
@ -140,7 +153,7 @@ Htk.Repeater = new Class
break;
}
case Db.Model.Status.LOADING:
this._showMessage (_('Loading'), 'loader-black.gif');
this._showMessage (_('Loading'), null);
break;
case Db.Model.Status.CLEAN:
this._showMessage (this.emptyMessage, 'refresh.svg');
@ -166,10 +179,19 @@ Htk.Repeater = new Class
div.className = 'message';
this._container.appendChild (div);
if (src)
{
var img = document.createElement ('img');
img.alt = '';
img.src = 'image/'+ src;
div.appendChild (img);
}
else
{
var spinner = new Htk.Spinner ();
spinner.start ();
div.appendChild (spinner.getNode ());
}
div.appendChild (document.createTextNode (message));
}

27
web/js/htk/spinner.js Executable file
View File

@ -0,0 +1,27 @@
Htk.Spinner = new Class
({
Extends: Htk.Widget
,Tag: 'htk-spinner'
,initialize: function (props)
{
var loader = this.createElement ('div');
loader.className = 'htk-spinner';
var spin = document.createElement ('div');
loader.appendChild (spin);
this.spin = spin;
this.parent (props);
}
,start: function ()
{
Vn.Node.addClass (this.spin, 'spinner');
}
,stop: function ()
{
Vn.Node.removeClass (this.spin, 'spinner');
}
});

View File

@ -41,12 +41,14 @@
}
.htk-grid .message
{
height: 5em;
padding: 1.5em;
}
.htk-grid .message img
.htk-grid .message > img,
.htk-grid .message > .htk-spinner
{
display: inline-block;
vertical-align: middle;
padding: 0.8em;
padding-right: 0.8em;
height: 1.8em;
}
.htk-grid > tbody tr
@ -121,17 +123,18 @@
.htk-repeater > .message
{
padding: 1em;
padding: 1.5em;
text-align: center;
}
.htk-repeater > .message > *
{
vertical-align: middle;
}
.htk-repeater > .message > img
.htk-repeater > .message > img,
.htk-repeater > .message > .htk-spinner
{
padding: 0.8em;
padding-left: 0;
display: inline-block;
padding-right: .8em;
height: 1.8em;
}
@ -438,3 +441,74 @@
opacity: .7;
}
/* Search entry */
.htk-search-entry
{
background-color: white;
height: 2.2em;
}
.htk-search-entry > img
{
margin: 0;
height: 1.5em;
margin-left: .4em;
vertical-align: middle;
}
.htk-search-entry > .entry
{
margin: 0;
border: none;
width: 8em;
box-shadow: none;
}
.htk-search-entry > .entry:focus
{
background-color: initial;
}
/* Loader */
.htk-spinner
{
position: relative;
display: inline-block;
box-sizing: border-box;
}
.htk-spinner > .spinner
{
width: 1.8em;
height: 1.8em;
}
.htk-spinner > .spinner:before
{
content: 'Loading…';
position: absolute;
left: 0;
width: 1.2em;
height: 1.2em;
}
.htk-spinner > .spinner:not(:required):before
{
content: '';
border-radius: 50%;
border: .3em solid transparent;
border-top-color: #666;
border-left-color: #666;
animation: spinner 1s linear infinite;
-webkit-animation: spinner 1s linear infinite;
}
.htk-spinner.dark > .spinner:not(:required):before
{
border-top-color: white;
border-left-color: white;
}
@keyframes spinner
{
to {transform: rotate(360deg);}
}
@-webkit-keyframes spinner
{
to {-webkit-transform: rotate(360deg);}
}

View File

@ -91,6 +91,16 @@ Sql.Batch = new Class
new Sql.Value ({param: param}));
}
,getValue: function (id)
{
var object = this.objects[id];
if (object instanceof Sql.Value)
return object.value;
return null;
}
,addParams: function (params)
{
for (var id in params)

View File

@ -18,9 +18,15 @@ Sql.FilterItem = new Class
{
return this._disabled;
}
},
primary:
{
type: Boolean
}
}
,primary: true
,isReady: function ()
{
if (this._disabled)

View File

@ -20,7 +20,7 @@ Sql.Filter = new Class
var e = this.exprs.getArray ();
for (var i = 0; i < e.length; i++)
if (e[i].isReady ())
if (e[i].isReady () && e[i].primary)
return true;
return false;

View File

@ -275,7 +275,6 @@ Vn.Builder = new Class
var objectProps = {};
var childs = [];
var events = {};
var handler;
var context = {
klass: klass,
@ -293,8 +292,11 @@ Vn.Builder = new Class
var attribute = a[i].nodeName;
var value = a[i].nodeValue;
if (handler = this._getEventHandler (attribute, value))
if (this._isEvent (attribute))
{
var handler = this._getMethod (value)
if (handler)
events[attribute.substr (3)] = handler;
}
else if (!/^(id|property)$/.test (attribute))
@ -432,8 +434,13 @@ Vn.Builder = new Class
var attribute = a[i].nodeName;
var value = a[i].nodeValue;
if (handler = this._getEventHandler (attribute, value))
if (this._isEvent (attribute))
{
var handler = this._getMethod (value);
if (handler)
events[attribute.substr (3)] = handler;
}
else if (attribute !== 'id')
attributes[attribute] = this._translateValue (value);
}
@ -528,21 +535,18 @@ Vn.Builder = new Class
}
catch (e)
{
method = null;
method = undefined;
}
if (method === null)
if (method === undefined)
this._showError ('Function \'%s\' not found', value);
return method;
}
,_getEventHandler: function (attribute, value)
,_isEvent: function (attribute)
{
if (!(/^on-\w+/.test (attribute)))
return null;
return this._getMethod (value);
return /^on-\w+/.test (attribute);
}
,_replaceFunc: function (token)

View File

@ -12,7 +12,7 @@ Vn.Locale =
if (!this.language)
{
var language = navigator.language.substr (0, 2);
this.language = language ? language : 'es';
this.language = language ? language : 'en';
}
}

View File

@ -3,7 +3,7 @@
,"SearchResults": "Resultats de cerca"
,"SelectFamily": "Selecciona una família"
,"SelectSubtype": "Selecciona un subtipus en el menú de la dreta"
,"Select filter from right menu": "Selecciona un filtre en el menú de la dreta"
,"ArticleNotFound": "Artcle no trobat"
,"ArticleNotAvailable": "Article no disponible"

View File

@ -1,7 +1,7 @@
{
"OrderDetail": "Detall de l'encarrec"
,"Print": "Imprimir albarà"
,"Print delivery note": "Imprimir albarà"
,"TicketNumber:": "N ticket:"
,"DateExit:": "Data d'enviament:"

View File

@ -26,4 +26,6 @@ Vn.Locale.add
,"Close": "Tancar"
,"Previous": "Anterior"
,"Next": "Següent"
,"Search": "Cercar"
,"Search...": "Cercar..."
});

View File

@ -3,7 +3,7 @@
,"SearchResults": "Search results"
,"SelectFamily": "Select family"
,"SelectSubtype": "Select a filter from the right menu"
,"Select filter from right menu": "Select a filter from the right menu"
,"ArticleNotFound": "Item not found"
,"ArticleNotAvailable": "Item not available"

View File

@ -18,7 +18,7 @@
,"Modify": "Modify"
,"Confirm": "Confirm"
,"OrderPlacedSuccessfully": "Your order has been successfully completed"
,"OrderPlacedSuccessfully": "Your order has been confirmed successfully"
,"OrderReserved": "We've booked your order but it seems that there have been problems with payment. Contact your sales."
,"Accept": "Accept"
,"PayNow": "Pay now"

View File

@ -1,7 +1,7 @@
{
"OrderDetail": "Order detail"
,"Print": "Print delivery note"
,"Print delivery note": "Print delivery note"
,"TicketNumber:": "Ticket number:"
,"DateExit:": "Delivery date:"

View File

@ -9,8 +9,8 @@ Vn.Locale.add
,"Login mail": "clientes@verdnatura.es"
,"Login phone": "+34 607 562 391"
,"You've been too idle": "You've been too idle and session time has expired."
,"Invalid login": "Username or password incorrect. Remember that case-sensitive."
,"You've been too idle": "You have been idle too long and your session has expired."
,"Invalid login": "Username or password incorrect. Remember that it is case-sensitive."
,"There was an internal error": "There was an internal error"
,"Menu": "Menu"

View File

@ -26,4 +26,6 @@ Vn.Locale.add
,"Close": "Close"
,"Previous": "Previous"
,"Next": "Next"
,"Search": "Search"
,"Search...": "Search..."
});

View File

@ -3,7 +3,7 @@
,"SearchResults": "Resultados de búsqueda"
,"SelectFamily": "Selecciona una familia"
,"SelectSubtype": "Selecciona un subtipo en el menú de la derecha"
,"Select filter from right menu": "Selecciona un filtro en el menú de la derecha"
,"ArticleNotFound": "Artículo no encontrado"
,"ArticleNotAvailable": "Artículo no disponible"

View File

@ -1,7 +1,7 @@
{
"OrderDetail": "Detalle del pedido"
,"Print": "Imprimir albarán"
,"Print delivery note": "Imprimir albarán"
,"TicketNumber:": "Nº ticket:"
,"DateExit:": "Fecha de envío:"

View File

@ -26,4 +26,6 @@ Vn.Locale.add
,"Close": "Cerrar"
,"Previous": "Anterior"
,"Next": "Siguiente"
,"Search": "Buscar"
,"Search...": "Buscar..."
});

View File

@ -3,7 +3,7 @@
,"SearchResults": "Résultats de la recherche"
,"SelectFamily": "Choisissez une famille"
,"SelectSubtype": "Sélectionnez le sous-menu sur la droite"
,"Select filter from right menu": "Sélectionnez un filtre dans le menu de droite"
,"ArticleNotFound": "Article non trouvé"
,"ArticleNotAvailable": "Article non disponible"

View File

@ -1,7 +1,7 @@
{
"OrderDetail": "Détails de la commande"
,"Print": "Imprimer bulletin de livraison"
,"Print delivery note": "Imprimer bulletin de livraison"
,"TicketNumber:": "Num ticket:"
,"DateExit:": "Date d'envoi:"

View File

@ -26,4 +26,6 @@ Vn.Locale.add
,"Close": "Croche"
,"Previous": "Précédent"
,"Next": "Suivant"
,"Search": "Recherche"
,"Search...": "Recherche..."
});

View File

@ -3,7 +3,7 @@
,"SearchResults": "Search results"
,"SelectFamily": "Select family"
,"SelectSubtype": "Select a filter from the right menu"
,"Select filter from right menu": "Зөв цэс нь шүүлтүүр сонгоно уу"
,"ArticleNotFound": "Item not found"
,"ArticleNotAvailable": "Item not available"

View File

@ -1,7 +1,7 @@
{
"OrderDetail": "Order detail"
,"Print": "Print delivery note"
,"Print delivery note": "Print delivery note"
,"TicketNumber:": "Ticket number:"
,"DateExit:": "Delivery date:"

View File

@ -26,4 +26,6 @@ Vn.Locale.add
,"Close": "Close"
,"Previous": "Previous"
,"Next": "Next"
,"Search": "хайх"
,"Search...": "хайх..."
});

View File

@ -0,0 +1,21 @@
Vn.DeliveryNote = new Class
({
Extends: Vn.Report
,subtotalRenderer: function (column, form)
{
column.value = this.subtotal (form);
}
,subtotal: function (form)
{
var price = form.get ('price');
var discount = form.get ('discount');
if (price && form.get ('fixed'))
return form.get ('amount') * price * ((100 - discount) / 100);
else
return null;
}
});

View File

@ -0,0 +1,45 @@
*
{
font-size: 4mm;
}
.sheet
{
height: auto;
}
h1
{
font-weight: normal;
font-size: 200%;
text-align: center;
margin: 0 auto;
margin-bottom: 8mm;
}
.htk-grid
{
border-collapse: collapse;
width: 100%;
margin: 0 auto;
padding: 0;
}
thead > tr
{
border-bottom: 1px solid #333;
height: 10mm;
}
th
{
font-weight: normal;
}
td
{
padding-left: 2mm;
}
tbody > tr
{
height: 18mm;
}
.cell-image > img
{
width: 15mm;
}

View File

@ -0,0 +1,97 @@
<vn>
<vn-group>
<db-form id="ticket">
<db-model property="model" id="ticket-data" conn="conn" batch="batch">
<custom>
SELECT t.id, date, a.Agencia, note, p.name province,
zip_code, city, c.name, consignee, invoice
FROM ticket_view t
JOIN address_view c ON t.address_id = c.id
JOIN vn2008.Agencias a ON t.agency_id = a.Id_Agencia
JOIN vn2008.province p ON c.province_id = p.province_id
WHERE t.id = #ticket
</custom>
</db-model>
</db-form>
</vn-group>
<div id="report" class="sheet">
<table class="form">
<tbody>
<tr>
<td class="label">
<label><t>TicketNumber:</t></label>
</td>
<td>
<htk-text column="id" form="ticket"/>
</td>
</tr>
<tr>
<td class="label">
<label><t>DateExit:</t></label>
</td>
<td>
<htk-date-chooser column="date" form="ticket" editable="false"/>
</td>
</tr>
<tr>
<td class="label">
<label><t>SendMethod:</t></label>
</td>
<td>
<htk-text column="Agencia" form="ticket"/>
</td>
</tr>
<tr>
<td class="label">
<label><t>Notes:</t></label>
</td>
<td>
<htk-text column="note" form="ticket"/>
</td>
</tr>
<tr>
<td class="label">
<label for="total"><t>Subtotal:</t></label>
</td>
<td>
<htk-text format="%.2d€">
<db-calc-sum func="subtotal" model="movements"/>
</htk-text>
</td>
</tr>
</tbody>
</table>
<htk-grid model="ticket-data">
<htk-column-spin title="_PC" column="zip_code"/>
<htk-column-text title="_City" column="city"/>
<htk-column-text title="_Province" column="province"/>
<htk-column-text title="_Address" column="name"/>
<htk-column-text title="_Consignee" column="consignee"/>
</htk-grid>
<htk-grid>
<db-model property="model" id="movements" conn="conn" batch="batch">
<custom>
SELECT m.item_id, amount, concept, Categoria, Medida, Tallos, Color,
Abreviatura, IF(fixed != FALSE, price, NULL) price, fixed, discount
FROM ticket_row_view m
INNER JOIN vn2008.Articles a
ON m.item_id = a.Id_Article AND ticket_id = #ticket
LEFT JOIN vn2008.Origen o
ON a.id_origen = o.id
ORDER BY concept
</custom>
</db-model>
<htk-column-spin title="_ItemNumber" column="item_id"/>
<htk-column-spin title="_Amount" column="amount"/>
<htk-column-text title="_Item" column="concept"/>
<htk-column-text title="_Category" column="Categoria"/>
<htk-column-text title="_S1" column="Medida"/>
<htk-column-text title="_Stems" column="Tallos"/>
<htk-column-text title="_Color" column="Color"/>
<htk-column-text title="_Origin" column="Abreviatura"/>
<htk-column-spin title="_Price" column="price" unit="€" digits="2"/>
<htk-column-spin title="_Desc" column="discount" unit="%"/>
<htk-column-spin title="_Subtotal" unit="€" digits="2" renderer="subtotalRenderer"/>
</htk-grid>
</div>
</vn>

View File

@ -2,4 +2,364 @@
Vn.ShelvesReport = new Class
({
Extends: Vn.Report
,nItem: -1
,nColors: 5
,open: function (batch)
{
this.batch = batch;
this.title = batch.getValue ('title');
this.maxAmount = batch.getValue ('max-amount');
this.showPacking = batch.getValue ('show-packing');
this.stack = batch.getValue ('stack');
var query =
'SELECT id, name, width, height, depth, max_height, tray_height, '+
'first_tray_elevation, tray_density, vspacing, hspacing '+
'FROM shelf WHERE id = #shelf; '+
'CALL item_organizer (#wh, #date, #family, #filter)';
this.conn.execQuery (query, this.onQueryExec.bind (this), this.batch);
}
,onQueryExec: function (resultSet)
{
// Fetch query data
var res = resultSet.fetchResult ();
res.next ();
var maxWidth = 170;
var maxHeight = 200;
var scale = maxWidth / res.get ('width');
if (res.get ('max_height') * scale > maxHeight)
scale = maxHeight / res.get ('max_height');
var shelf = this.shelf =
{
width: res.get ('width') * scale
,height: res.get ('height') * scale
,depth: res.get ('depth') * scale
,maxHeight: res.get ('max_height') * scale
,trayHeight: res.get ('tray_height') * scale
,firstTrayElevation: res.get ('first_tray_elevation') * scale
,trayDensity: res.get ('tray_density') * scale
,vspacing: res.get ('vspacing') * scale
,hspacing: res.get ('hspacing') * scale
};
var items = this.items = [];
var remainings = this.remainings = [];
var res = resultSet.fetchResult ();
if (res.data.length == 0)
{
Htk.Toast.showError (_('No items found, check that all fields are correct'));
return;
}
var boxScale = scale * 10;
while (res.next ())
if (!this.maxAmount || res.get ('etiquetas') <= this.maxAmount)
{
items.push ({
id: res.get ('Id_Article')
,name: res.get ('Article')
,packing: res.get ('packing')
,amount: res.get ('etiquetas')
,boxHeight: res.get ('z') * boxScale
,boxWidth: res.get ('x') * boxScale
,boxDepth: res.get ('y') * boxScale
});
}
else
{
remainings.push ({
id: res.get ('Id_Article')
,name: res.get ('Article')
,packing: res.get ('packing')
,amount: res.get ('etiquetas')
});
}
// Intializes the allocator
alloc = this.alloc = new Vn.Allocator ();
alloc.items = items;
alloc.shelfFunc = this.drawShelf.bind (this);
alloc.boxFunc = this.drawBox.bind (this);
alloc.stack = this.stack;
alloc.nTrays = Math.ceil (
(shelf.height - shelf.firstTrayElevation) /
(shelf.trayHeight + shelf.trayDensity)
);
alloc.width = shelf.width - shelf.hspacing * 2;
alloc.depth = shelf.depth;
alloc.trayHeight = shelf.trayHeight - shelf.vspacing;
alloc.topTrayHeight = shelf.maxHeight - shelf.vspacing
- shelf.firstTrayElevation - (alloc.nTrays - 1) * shelf.trayHeight;
// Opens the report
this.createWindow ();
}
,onWindowCreate: function ()
{
// Remaining amount
var remainings = this.remainings;
if (remainings.length > 0)
{
var sheet = this.doc.createElement ('div');
sheet.className = 'sheet';
this.doc.body.appendChild (sheet);
var title = this.doc.createElement ('h1');
title.className = 'title';
title.appendChild (this.doc.createTextNode (this.title));
sheet.appendChild (title);
var subtitle = this.doc.createElement ('h2');
subtitle.className = 'subtitle';
subtitle.appendChild (this.doc.createTextNode (_('Pallets')));
sheet.appendChild (subtitle);
var ul = this.doc.createElement ('ul');
sheet.appendChild (ul);
for (var i = 0; i < remainings.length; i++)
{
var li = this.doc.createElement ('li');
ul.appendChild (li);
var span = this.doc.createElement ('span');
span.className = 'item-id';
span.appendChild (this.doc.createTextNode (remainings[i].id.toLocaleString ()));
li.appendChild (span);
var span = this.doc.createElement ('span');
span.className = 'item';
span.appendChild (this.doc.createTextNode (remainings[i].name));
li.appendChild (span);
if (this.showPacking)
span.appendChild (this.doc.createTextNode (' '+ remainings[i].packing));
var span = this.doc.createElement ('span');
span.className = 'amount';
span.appendChild (this.doc.createTextNode (remainings[i].amount));
li.appendChild (span);
}
}
// Draws the shelves
this.alloc.run ();
this.drawShelfEnding ();
}
,drawShelf: function (allocator, item)
{
var shelf = this.shelf;
var sheet = this.doc.createElement ('div');
sheet.className = 'sheet';
this.doc.body.appendChild (sheet);
// Draws the title
var pageNumber = this.doc.createElement ('h1');
pageNumber.className = 'page-number';
pageNumber.appendChild (this.doc.createTextNode (allocator.currentShelf + 1));
sheet.appendChild (pageNumber);
var title = this.doc.createElement ('h1');
title.className = 'title';
title.appendChild (this.doc.createTextNode (this.title));
sheet.appendChild (title);
var subtitle = this.doc.createElement ('h2');
subtitle.className = 'subtitle';
subtitle.appendChild (this.doc.createTextNode (item.id.toLocaleString ()));
sheet.appendChild (subtitle);
this.drawShelfEnding ();
this.lastSubtitle = subtitle;
// Draws the shelf
var shelfDiv = this.shelfDiv = this.doc.createElement ('div');
shelfDiv.className = 'shelf';
shelfDiv.style.width = this.mm (shelf.width);
shelfDiv.style.height = this.mm (shelf.maxHeight);
sheet.appendChild (shelfDiv);
// Draws trays
var lastTrayY = shelf.firstTrayElevation;
if (shelf.trayHeight > 0)
while (lastTrayY + shelf.trayDensity < shelf.height)
{
var tray = this.doc.createElement ('div');
tray.className = 'tray';
tray.style.width = this.mm (shelf.width);
tray.style.height = this.mm (shelf.trayDensity);
tray.style.bottom = this.mm (lastTrayY);
shelfDiv.appendChild (tray);
lastTrayY += shelf.trayHeight + shelf.trayDensity;
}
}
,drawShelfEnding: function ()
{
if (this.lastSubtitle)
this.lastSubtitle.appendChild (
this.doc.createTextNode (' - '+ this.lastItem.id.toLocaleString ()));
}
,mm: function (size)
{
return size.toFixed (2) +'mm';
}
,drawBox: function (allocator, item, amount)
{
if (item.boxWidth == 0 || item.boxHeight == 0)
return;
var shelf = this.shelf;
var x = allocator.trayX + shelf.hspacing;
var y = allocator.trayY
+ shelf.firstTrayElevation + shelf.trayDensity
+ allocator.currentTray * (shelf.trayHeight + shelf.trayDensity);
var box = this.doc.createElement ('div');
box.className = 'box';
this.shelfDiv.appendChild (box);
box.style.left = this.mm (x);
box.style.bottom = this.mm (y);
box.style.width = this.mm (item.boxWidth);
box.style.height = this.mm (item.boxHeight);
if (amount == 0)
this.nItem++;
var nColor = this.nItem % this.nColors;
Vn.Node.addClass (box, 'color'+ nColor);
if (amount == 0 || allocator.firstShelfBox)
{
var fontSize = item.boxWidth / 5.2;
if (fontSize > item.boxHeight - 1)
fontSize = item.boxHeight - 1;
var boxLabel = this.doc.createElement ('div');
boxLabel.className = 'box-label';
boxLabel.style.fontSize = this.mm (fontSize);
boxLabel.appendChild (this.doc.createTextNode (item.id.toLocaleString ()));
box.appendChild (boxLabel);
}
this.lastItem = item;
}
});
Vn.Allocator = new Class
({
addShelf: function (item)
{
this.currentShelf++;
this.firstShelfBox = true;
if (this.shelfFunc)
this.shelfFunc (this, item);
}
,addTray: function (item)
{
if (this.currentTray <= 0)
{
this.addShelf (item);
this.currentTray = this.nTrays - 1;
}
else
this.currentTray--;
this.trayX = 0;
}
,addColumn: function (item)
{
if (this.trayX + this.columnWidth + item.boxWidth > this.width
|| this.currentTray == -1)
this.addTray (item);
else
this.trayX += this.columnWidth;
this.trayY = 0;
this.columnWidth = item.boxWidth;
this.lastBoxWidth = item.boxWidth;
}
,addBox: function (item, amount)
{
var trayHeight = this.trayHeight;
if (this.currentTray == this.nTrays - 1)
trayHeight = this.topTrayHeight;
if (this.trayY + item.boxHeight > trayHeight
|| item.boxWidth > this.lastBoxWidth
|| (!this.stack && amount == 0))
this.addColumn (item);
if (this.boxFunc)
this.boxFunc (this, item, amount);
this.trayY += item.boxHeight;
if (item.boxWidth < this.lastBoxWidth)
this.lastBoxWidth = item.boxWidth;
}
,run: function ()
{
this.firstShelfBox = false;
this.currentShelf = -1;
this.currentTray = -1;
this.columnWidth = 0;
this.lastBoxWidth = 0;
this.trayX = 0;
this.trayY = 0;
this.remaining = false;
for (var i = 0; i < this.items.length; i++)
{
var item = this.items[i];
var boxIncrement = Math.floor (this.depth / item.boxDepth);
if (boxIncrement < 1)
boxIncrement = 1;
for (var amount = 0; amount < item.amount; amount += boxIncrement)
{
this.addBox (item, amount);
this.firstShelfBox = false;
}
}
return this.currentShelf + 1;
}
});