forked from verdnatura/hedera-web
Version alpha2 del bionic
This commit is contained in:
parent
609c90b06e
commit
7355557164
|
@ -5,7 +5,6 @@ Vn.Address = new Class
|
|||
|
||||
,activate: function ()
|
||||
{
|
||||
this.$('model').mode = Db.Model.Mode.ON_DEMAND;
|
||||
this.$('model').setInfo ('a', 'address_view', 'hedera', ['id'], 'id');
|
||||
this.$('model').setDefault ('customer_id', 'a',
|
||||
new Sql.Func ({schema: 'account', name: 'user_get_id'}));
|
||||
|
@ -13,7 +12,7 @@ Vn.Address = new Class
|
|||
|
||||
,onStatusChange: function (form)
|
||||
{
|
||||
if (this.$('address').value == 0)
|
||||
if (form.ready && this.$('address').value == 0)
|
||||
form.insertRow ();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</vn-param>
|
||||
<db-form id="iter" on-status-changed="onStatusChange">
|
||||
<db-param id="country" one-way="true" column="country_id"/>
|
||||
<db-model id="model" updatable="true" on-operations-done="onOperationsDone">
|
||||
<db-model id="model" updatable="true" mode="ON_DEMAND" on-operations-done="onOperationsDone">
|
||||
SELECT a.id, a.name, a.consignee, a.city, a.zip_code, a.province_id, c.Id country_id
|
||||
FROM address_view a
|
||||
LEFT JOIN vn2008.province p ON p.province_id = a.province_id
|
||||
|
|
|
@ -2,23 +2,34 @@
|
|||
Vn.Basket = new Class
|
||||
({
|
||||
Extends: Vn.Module
|
||||
|
||||
,orderId: null
|
||||
|
||||
,activate: function () {}
|
||||
|
||||
,onCatalogClick: function ()
|
||||
,activate: function ()
|
||||
{
|
||||
Vn.Cookie.set ('order', this.$('order').value);
|
||||
this.hash.set ({'form': 'ecomerce/catalog'});
|
||||
var query = 'CALL basket_check ()';
|
||||
this.conn.execQuery (query, this.onBasketCheck.bind (this));
|
||||
}
|
||||
|
||||
,onBasketCheck: function (resultSet)
|
||||
{
|
||||
var res = resultSet.fetchResult ();
|
||||
|
||||
if (!res.next())
|
||||
return;
|
||||
|
||||
if (res.get ('order_id'))
|
||||
{
|
||||
if (res.get ('refresh') && res.get ('nrows') > 0)
|
||||
(new Htk.Toast ()).showWarning (_('OrderItemsUpdated'));
|
||||
|
||||
this.$('order').value = res.get ('order_id');
|
||||
}
|
||||
else
|
||||
this.hash.set ({'form': 'ecomerce/checkout'});
|
||||
}
|
||||
|
||||
,onConfigureClick: function ()
|
||||
{
|
||||
this.hash.set ({
|
||||
'form': 'ecomerce/checkout',
|
||||
'order': this.$('order').value
|
||||
});
|
||||
this.hash.set ({'form': 'ecomerce/checkout'});
|
||||
}
|
||||
|
||||
,onCheckoutClick: function ()
|
||||
|
@ -80,3 +91,5 @@ Vn.Basket = new Class
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<vn>
|
||||
<vn-group>
|
||||
<vn-param id="order">
|
||||
<vn-hash-link key="order"/>
|
||||
</vn-param>
|
||||
<vn-param id="order"/>
|
||||
<db-form id="order-form">
|
||||
<db-model updatable="true">
|
||||
SELECT id, date_send, agency_id, wh_id
|
||||
|
@ -21,7 +19,7 @@
|
|||
<div class="header">
|
||||
<h1><t>ShoppingBasket</t></h1>
|
||||
<div class="action-bar">
|
||||
<button on-click="onConfigureClick">
|
||||
<button on-click="onConfigureClick">
|
||||
<img src="image/dark/preferences.svg" alt=""/>
|
||||
<t>ConfigureOrder</t>
|
||||
</button>
|
||||
|
@ -30,7 +28,7 @@
|
|||
<t>Checkout</t>
|
||||
</button>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<div class="clear"/>
|
||||
</div>
|
||||
<div>
|
||||
<htk-grid show-header="false">
|
||||
|
|
|
@ -7,30 +7,17 @@ Vn.Catalog = new Class
|
|||
|
||||
,activate: function ()
|
||||
{
|
||||
this.$('items-model').setInfo ('m', 'order_row_view', 'hedera', ['id'], 'id');
|
||||
this.$('items-model').setInfo ('a', 'Articles', 'vn2008', ['Id_Article']);
|
||||
|
||||
this.popup = new Htk.Popup ();
|
||||
this.popup.setChildNode (this.$('lots-popup'));
|
||||
|
||||
this.$('warehouse').value = 1;
|
||||
this.$('date').value = new Date ();
|
||||
|
||||
var orderId = Vn.Cookie.getInt ('order');
|
||||
|
||||
if (!orderId)
|
||||
this.configureView ();
|
||||
else
|
||||
this.$('order-batch').addValue ('order', orderId);
|
||||
}
|
||||
|
||||
,onRealmsReload: function (model, status)
|
||||
{
|
||||
if (status == Db.Model.Status.READY)
|
||||
{
|
||||
this.onRealmChange ();
|
||||
this.onTypeChange ();
|
||||
}
|
||||
if (status != Db.Model.Status.READY)
|
||||
return;
|
||||
|
||||
this.onRealmChange ();
|
||||
this.onTypeChange ();
|
||||
}
|
||||
|
||||
,onRealmChange: function ()
|
||||
|
@ -132,49 +119,9 @@ Vn.Catalog = new Class
|
|||
this.hideMenuCallback = null;
|
||||
}
|
||||
|
||||
,configureView: function ()
|
||||
{
|
||||
var orderId = 0;
|
||||
var grid = this.$('items-grid');
|
||||
var orderForm = this.$('order-form');
|
||||
|
||||
if (orderForm.numRows > 0)
|
||||
{
|
||||
orderForm.row = 0;
|
||||
orderId = orderForm.get ('id');
|
||||
|
||||
Vn.Node.setText (this.$('basket-button'), _('ShoppingBasket'));
|
||||
|
||||
var items = this.$('items-model');
|
||||
/* items.updatable = true;
|
||||
items.setDefaultFromColumn ('item_id', 'm', 'Id_Article');
|
||||
items.setDefaultFromValue ('order_id', 'm', orderId);
|
||||
*/
|
||||
this.$('warehouse').master = orderForm.getParam ('wh_id');
|
||||
this.$('date').master = orderForm.getParam ('date_send');
|
||||
}
|
||||
else
|
||||
Vn.Cookie.unset ('order');
|
||||
|
||||
this.$('order').value = orderId;
|
||||
this.$('basket-button').disabled = false;
|
||||
}
|
||||
|
||||
,onOrderFormChange: function (form)
|
||||
{
|
||||
if (form.ready)
|
||||
this.configureView ();
|
||||
}
|
||||
|
||||
,onBasketClick: function ()
|
||||
{
|
||||
if (Vn.Cookie.check ('order'))
|
||||
this.hash.set ({
|
||||
'form': 'ecomerce/basket',
|
||||
'order': Vn.Cookie.get ('order')
|
||||
});
|
||||
else
|
||||
this.hash.set ({'form': 'ecomerce/checkout'});
|
||||
this.hash.set ({'form': 'ecomerce/basket'});
|
||||
}
|
||||
|
||||
,featuresRender: function (renderer, form)
|
||||
|
@ -315,8 +262,9 @@ Htk.Realm = new Class
|
|||
,_model: null
|
||||
,selectedImg: null
|
||||
|
||||
,initialize: function (mod)
|
||||
,initialize: function (props)
|
||||
{
|
||||
this.parent (props);
|
||||
this.createElement ('div');
|
||||
this.node.className = 'htk-realm';
|
||||
}
|
||||
|
|
|
@ -249,10 +249,6 @@ button.confirm > img
|
|||
{
|
||||
background-color: #777;
|
||||
}
|
||||
.items > thead th:hover
|
||||
{
|
||||
background-color: #333;
|
||||
}
|
||||
.items > tbody > tr
|
||||
{
|
||||
height: 6em;
|
||||
|
|
|
@ -3,20 +3,11 @@
|
|||
<vn-param id="type" on-changed="onTypeChange">
|
||||
<vn-hash-link key="type"/>
|
||||
</vn-param>
|
||||
<vn-param id="order"/>
|
||||
<vn-param id="warehouse"/>
|
||||
<vn-param id="date"/>
|
||||
<vn-param id="search"/>
|
||||
<db-model id="realms-model" on-status-changed="onRealmsReload">
|
||||
SELECT id, reino, color FROM vn2008.reinos
|
||||
WHERE display != FALSE ORDER BY reino
|
||||
</db-model>
|
||||
<db-form id="order-form" on-status-changed="onOrderFormChange">
|
||||
<db-model updatable="true">
|
||||
SELECT id, date_send, wh_id FROM order_view WHERE id = #order
|
||||
<sql-batch property="batch" id="order-batch"/>
|
||||
</db-model>
|
||||
</db-form>
|
||||
<sql-filter type="AND" id="filter">
|
||||
<sql-filter-item type="EQUAL" id="sql-type">
|
||||
<sql-field name="tipo_id"/>
|
||||
|
@ -53,30 +44,6 @@
|
|||
</sql-batch>
|
||||
</db-model>
|
||||
</vn-group>
|
||||
<div id="lots-popup" class="lots-popup">
|
||||
<htk-grid class="lots-grid" model="item-lots" show-header="false">
|
||||
<htk-column-spin title="_Price" column="price" unit="€" digits="2"/>
|
||||
<htk-column-text title="_Pack" column="grouping" format="x%.0d"/>
|
||||
<htk-column-button
|
||||
column="id"
|
||||
image="image/add.svg"
|
||||
tip="_Add"
|
||||
on-clicked="onAddLotClick"/>
|
||||
</htk-grid>
|
||||
<div class="amount">
|
||||
<button on-click="onEraseClick" title="_Erase" class="erase">
|
||||
<img
|
||||
src="image/dark/delete.svg"
|
||||
alt="_Erase"/>
|
||||
</button>
|
||||
<htk-text id="amount"/>
|
||||
<button on-click="onConfirmClick" title="_Confirm" class="confirm">
|
||||
<img
|
||||
src="image/dark/ok.svg"
|
||||
alt="_Confirm"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="form" class="catalog">
|
||||
<div class="center">
|
||||
<div class="main">
|
||||
|
@ -122,8 +89,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="menu" class="menu" on-click="onMenuClick">
|
||||
<button disabled="true" id="basket-button" class="basket" on-click="onBasketClick">
|
||||
<t>StartOrder</t>
|
||||
<button class="basket" on-click="onBasketClick">
|
||||
<t>ShoppingBasket</t>
|
||||
</button>
|
||||
<htk-realm id="realms" model="realms-model" on-changed="onRealmChange">
|
||||
<vn-param id="realm">
|
||||
|
@ -143,6 +110,30 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="lots-popup" class="lots-popup">
|
||||
<htk-grid class="lots-grid" model="item-lots" show-header="false">
|
||||
<htk-column-spin title="_Price" column="price" unit="€" digits="2"/>
|
||||
<htk-column-text title="_Pack" column="grouping" format="x%.0d"/>
|
||||
<htk-column-button
|
||||
column="id"
|
||||
image="image/add.svg"
|
||||
tip="_Add"
|
||||
on-clicked="onAddLotClick"/>
|
||||
</htk-grid>
|
||||
<div class="amount">
|
||||
<button on-click="onEraseClick" title="_Erase" class="erase">
|
||||
<img
|
||||
src="image/dark/delete.svg"
|
||||
alt="_Erase"/>
|
||||
</button>
|
||||
<htk-text id="amount"/>
|
||||
<button on-click="onConfirmClick" title="_Confirm" class="confirm">
|
||||
<img
|
||||
src="image/dark/ok.svg"
|
||||
alt="_Confirm"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<htk-repeater id="grid-view" form-id="item">
|
||||
<div class="item-box">
|
||||
|
|
|
@ -3,7 +3,71 @@ Vn.Checkout = new Class
|
|||
({
|
||||
Extends: Vn.Module
|
||||
|
||||
,activate: function () {}
|
||||
,activate: function ()
|
||||
{
|
||||
this.autoStepLocked = true;
|
||||
|
||||
this.$('order-model').setDefault ('customer_id', 'o',
|
||||
new Sql.Func ({schema: 'account', name: 'user_get_id'}));
|
||||
|
||||
if (this.$('order').value == 0)
|
||||
this.$('defaults').refresh ();
|
||||
else
|
||||
(new Htk.Toast ()).showWarning (_('RememberReconfiguringImpact'));
|
||||
}
|
||||
|
||||
,setDefaults: function ()
|
||||
{
|
||||
var o = this.$('order-form');
|
||||
var d = this.$('defaults');
|
||||
|
||||
if (this.$('order').value == 0 && d.ready && o.ready)
|
||||
{
|
||||
o.insertRow ();
|
||||
// o.set ('delivery_method_id', d.get ('delivery_method'));
|
||||
o.set ('date_send', new Date ());
|
||||
o.set ('agency_id', d.get ('agency_id'));
|
||||
o.set ('address_id', d.get ('address_id'));
|
||||
this.autoStepLocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
,onOrderReady: function ()
|
||||
{
|
||||
if (this.$('order').value != 0)
|
||||
this.autoStepLocked = false;
|
||||
}
|
||||
|
||||
,onOperationsDone: function ()
|
||||
{
|
||||
if (this.$('order').value == 0)
|
||||
{
|
||||
(new Htk.Toast ()).showMessage (_('OrderStarted'));
|
||||
this.hash.set ({'form': 'ecomerce/catalog'});
|
||||
}
|
||||
else
|
||||
this.conn.execQuery ('CALL basket_update ()',
|
||||
this.onBasketUpdated.bind (this));
|
||||
}
|
||||
|
||||
,onBasketUpdated: function ()
|
||||
{
|
||||
(new Htk.Toast ()).showMessage (_('OrderUpdated'));
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
,onConfirmClick: function ()
|
||||
{
|
||||
this.$('order-form').performOperations ();
|
||||
}
|
||||
|
||||
,onCancelClick: function ()
|
||||
{
|
||||
if (this.$('order').value == 0)
|
||||
this.hash.set ({'form': 'ecomerce/orders'});
|
||||
else
|
||||
this.hash.set ({'form': 'ecomerce/basket'});
|
||||
}
|
||||
|
||||
,agencySteps: ['delivery', 'date', 'address', 'agency', 'confirm-agency']
|
||||
,deliverySteps: ['delivery', 'date', 'address', null, 'confirm-delivery']
|
||||
|
@ -33,50 +97,47 @@ Vn.Checkout = new Class
|
|||
|
||||
var stepId = steps[stepIndex];
|
||||
|
||||
if (stepId)
|
||||
if (!stepId)
|
||||
return null;
|
||||
|
||||
switch (stepId)
|
||||
{
|
||||
if (stepId == 'date')
|
||||
{
|
||||
case 'date':
|
||||
Vn.Node.setText (this.$('date-question'), isDelivery ?
|
||||
_('OrderDateDeliveryQuestion'):
|
||||
_('OrderDatePickupQuestion'));
|
||||
this.$('calendar').goToSelectedMonth ();
|
||||
}
|
||||
|
||||
return this.$(stepId +'-step');
|
||||
break;
|
||||
case 'address':
|
||||
this.$('addresses').refresh ();
|
||||
break;
|
||||
case 'agency':
|
||||
this.$('agencies').refresh ();
|
||||
break;
|
||||
case 'pickup':
|
||||
this.$('warehouses').refresh ();
|
||||
break;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
,onDefaults: function (i)
|
||||
{
|
||||
if (!i.ready)
|
||||
return;
|
||||
|
||||
this.lockAssistant = true;
|
||||
this.$('rg-delivery').value = i.get ('delivery_method');
|
||||
this.$('date').value = new Date ();
|
||||
this.$('agency').value = i.get ('agency_id');
|
||||
this.$('address').value = i.get ('address_id');
|
||||
this.lockAssistant = false;
|
||||
|
||||
return this.$(stepId +'-step');
|
||||
}
|
||||
|
||||
,onFieldChange: function ()
|
||||
{
|
||||
if (!this.lockAssistant)
|
||||
if (!this.autoStepLocked)
|
||||
setTimeout (this.goNextStep.bind (this), 75);
|
||||
}
|
||||
|
||||
,addressRenderer: function (builder, index)
|
||||
{
|
||||
builder.$('address').addEventListener ('click',
|
||||
builder.$('address-div').addEventListener ('click',
|
||||
this.onAddressClick.bind (this, index));
|
||||
}
|
||||
|
||||
,onAddressClick: function (index)
|
||||
{
|
||||
this.$('address-form').row = index;
|
||||
this.$('address').value = this.$('address-form').get ('id');
|
||||
this.goNextStep ();
|
||||
}
|
||||
|
||||
|
@ -84,36 +145,5 @@ Vn.Checkout = new Class
|
|||
{
|
||||
this.$('assistant').moveNext ();
|
||||
}
|
||||
|
||||
,onConfirmClick: function ()
|
||||
{
|
||||
var batch = new Sql.Batch ();
|
||||
batch.addParam ('date', this.$('date'));
|
||||
batch.addParam ('delivery', this.$('rg-delivery'));
|
||||
batch.addParam ('agency', this.$('agency'));
|
||||
batch.addParam ('address', this.$('address'));
|
||||
|
||||
var sql = 'CALL order_new_beta (#date, #delivery, #agency, #address);';
|
||||
this.conn.execQuery (sql, this.onOrderCreate.bind (this), batch);
|
||||
}
|
||||
|
||||
,onOrderCreate: function (resultSet)
|
||||
{
|
||||
var orderId = resultSet.fetchValue ();
|
||||
|
||||
if (orderId)
|
||||
{
|
||||
Vn.Cookie.set ('order', orderId);
|
||||
this.hash.set ({'form': 'ecomerce/catalog'});
|
||||
(new Htk.Toast ()).showMessage (_('OrderStarted'));
|
||||
}
|
||||
else
|
||||
(new Htk.Toast ()).showMessage (_('ErrorCreatingOrder'));
|
||||
}
|
||||
|
||||
,onCancelClick: function ()
|
||||
{
|
||||
window.history.back();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
<vn>
|
||||
<vn-group>
|
||||
<vn-param id="date"/>
|
||||
<vn-param id="agency"/>
|
||||
<vn-param id="order-id">
|
||||
<vn-param id="order">
|
||||
<vn-hash-link key="order"/>
|
||||
</vn-param>
|
||||
<db-form id="defaults" on-iter-changed="onDefaults">
|
||||
<db-model>
|
||||
SELECT address_id, agency_id, delivery_method
|
||||
<db-form id="defaults" on-iter-changed="setDefaults">
|
||||
<db-model auto-load="false">
|
||||
SELECT delivery_method, address_id, agency_id
|
||||
FROM order_defaults_view
|
||||
</db-model>
|
||||
</db-form>
|
||||
<db-form id="address-form">
|
||||
<db-param column="id" id="address"/>
|
||||
<db-model id="addresses">
|
||||
SELECT a.id, a.consignee, p.name province, a.zip_code, a.city, a.name, a.active, c.Pais country
|
||||
FROM address_view a
|
||||
LEFT JOIN vn2008.province p ON a.province_id = p.province_id
|
||||
JOIN vn2008.Paises c ON c.Id = p.Paises_Id
|
||||
WHERE active != FALSE
|
||||
<db-form id="order-form" on-status-changed="setDefaults" on-iter-changed-after="onOrderReady">
|
||||
<db-model id="order-model" updatable="true" mode="ON_DEMAND" on-operations-done="onOperationsDone">
|
||||
SELECT id, delivery_method_id, date_send, agency_id, address_id, customer_id
|
||||
FROM order_view o WHERE id = #id
|
||||
<sql-batch property="batch">
|
||||
<item name="id" param="order"/>
|
||||
</sql-batch>
|
||||
</db-model>
|
||||
<db-param column="date_send" id="date"/>
|
||||
<db-param column="agency_id" id="agency"/>
|
||||
<db-param column="address_id" id="address"/>
|
||||
<db-param column="delivery_method_id" id="delivery"/>
|
||||
</db-form>
|
||||
</vn-group>
|
||||
<div id="form" class="checkout">
|
||||
|
@ -32,6 +33,7 @@
|
|||
<t>Cancel</t>
|
||||
</button>
|
||||
</div>
|
||||
<div class="clear"/>
|
||||
</div>
|
||||
<div class="form">
|
||||
<htk-assistant
|
||||
|
@ -40,16 +42,6 @@
|
|||
step-func="stepFunc"
|
||||
node="assistant-node"/>
|
||||
<div id="assistant-node">
|
||||
<div id="date-step">
|
||||
<h2 id="date-question"><t>OrderDateDeliveryQuestion</t></h2>
|
||||
<div class="answers">
|
||||
<htk-calendar
|
||||
id="calendar"
|
||||
class="thin-calendar"
|
||||
param="date"
|
||||
on-changed="onFieldChange"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="delivery-step">
|
||||
<h2><t>DeliveryOrPickupQuestion</t></h2>
|
||||
<div class="answers radio">
|
||||
|
@ -70,10 +62,29 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="date-step">
|
||||
<h2 id="date-question"><t>OrderDateDeliveryQuestion</t></h2>
|
||||
<div class="answers">
|
||||
<htk-calendar
|
||||
id="calendar"
|
||||
class="thin-calendar"
|
||||
param="date"
|
||||
on-changed="onFieldChange"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="address-step">
|
||||
<h2><t>AddressQuestion</t></h2>
|
||||
<db-form id="address-form">
|
||||
<db-model id="addresses" auto-load="false">
|
||||
SELECT a.id, a.consignee, p.name province, a.zip_code, a.city, a.name, a.active, c.Pais country
|
||||
FROM address_view a
|
||||
LEFT JOIN vn2008.province p ON a.province_id = p.province_id
|
||||
JOIN vn2008.Paises c ON c.Id = p.Paises_Id
|
||||
WHERE active != FALSE
|
||||
</db-model>
|
||||
</db-form>
|
||||
<htk-repeater model="addresses" form-id="iter" renderer="addressRenderer">
|
||||
<div class="answers target address" id="address">
|
||||
<div class="answers target address" id="address-div">
|
||||
<p class="consignee">
|
||||
<htk-text form="iter" column="consignee"/>
|
||||
</p>
|
||||
|
@ -87,7 +98,7 @@
|
|||
<h2><t>AgencyQuestion</t></h2>
|
||||
<div class="answers target">
|
||||
<htk-combo id="agency-combo" param="agency" on-changed="onFieldChange">
|
||||
<db-model property="model" id="agencies" result-index="1">
|
||||
<db-model property="model" id="agencies" auto-load="false" result-index="1">
|
||||
CALL agency_list_by_date (#date, #address);
|
||||
SELECT a.Id_Agencia, a.description
|
||||
FROM t_agency t
|
||||
|
@ -109,7 +120,7 @@
|
|||
<h2><t>PickupWarehouseQuestion</t></h2>
|
||||
<div class="answers target">
|
||||
<htk-combo id="warehouse-combo" param="agency" on-changed="onFieldChange">
|
||||
<db-model property="model" id="warehouses">
|
||||
<db-model property="model" id="warehouses" auto-load="false">
|
||||
SELECT a.Id_Agencia, SUBSTR(a.description, 5) description
|
||||
FROM vn2008.Agencias a
|
||||
JOIN vn2008.Vistas v ON a.Vista = v.vista_id
|
||||
|
|
|
@ -65,102 +65,3 @@ Vn.Confirm = new Class
|
|||
}
|
||||
});
|
||||
|
||||
Vn.Tpv = new Class
|
||||
({
|
||||
initialize: function (conn, hash)
|
||||
{
|
||||
this.conn = conn;
|
||||
this.hash = hash;
|
||||
|
||||
var tpvStatus = this.hash.get ('tpv_status');
|
||||
|
||||
if (tpvStatus)
|
||||
{
|
||||
var batch = new Sql.Batch ();
|
||||
batch.addValue ('transaction', this.hash.get ('tpv_order'));
|
||||
batch.addValue ('status', tpvStatus);
|
||||
|
||||
var query = 'CALL transaction_end (#transaction, #status)';
|
||||
|
||||
this.conn.execQuery (query, null, batch);
|
||||
}
|
||||
}
|
||||
|
||||
,pay: function (amount, company)
|
||||
{
|
||||
if (amount > 0)
|
||||
{
|
||||
var query = 'CALL transaction_start (#company, #amount)';
|
||||
|
||||
var batch = new Sql.Batch ();
|
||||
batch.addValue ('company', company);
|
||||
batch.addValue ('amount', parseInt (amount * 100));
|
||||
|
||||
this.conn.execQuery (query,
|
||||
this.onTransactionStart.bind (this), batch);
|
||||
}
|
||||
else if (!isNaN (amount))
|
||||
(new Htk.Toast ()).showError (_('AmountError'));
|
||||
}
|
||||
|
||||
,onTransactionStart: function (resultSet)
|
||||
{
|
||||
var res = resultSet.fetchResult ();
|
||||
|
||||
if (res && res.next ())
|
||||
{
|
||||
var form = document.createElement ('form');
|
||||
form.method = 'post';
|
||||
form.action = res.get ('url');
|
||||
document.body.appendChild (form);
|
||||
|
||||
var fieldsMap =
|
||||
{
|
||||
'Ds_Merchant_Amount': 'amount'
|
||||
,'Ds_Merchant_Order': 'ds_order'
|
||||
,'Ds_Merchant_MerchantCode': 'id'
|
||||
,'Ds_Merchant_Currency': 'currency'
|
||||
,'Ds_Merchant_TransactionType': 'transaction_type'
|
||||
,'Ds_Merchant_Terminal': 'terminal'
|
||||
,'Ds_Merchant_MerchantURL': 'merchant_url'
|
||||
,'Ds_Merchant_MerchantSignature': 'signature'
|
||||
,'Ds_Merchant_UrlOK': null
|
||||
,'Ds_Merchant_UrlKO': null
|
||||
};
|
||||
|
||||
for (var field in fieldsMap)
|
||||
{
|
||||
var input = document.createElement ('input');
|
||||
input.type = 'hidden';
|
||||
input.name = field;
|
||||
form.appendChild (input);
|
||||
|
||||
if (fieldsMap[field])
|
||||
input.value = res.get (fieldsMap[field]);
|
||||
}
|
||||
|
||||
var transactionId = res.get ('ds_order');
|
||||
form['Ds_Merchant_UrlOK'].value = this.makeUrl ('ok', transactionId);
|
||||
form['Ds_Merchant_UrlKO'].value = this.makeUrl ('ko', transactionId);
|
||||
|
||||
form.submit ();
|
||||
}
|
||||
else
|
||||
alert (_('PayError'));
|
||||
}
|
||||
|
||||
,makeUrl: function (status, order)
|
||||
{
|
||||
var path = location.protocol +'//'+ location.host;
|
||||
path += location.port ? ':'+ location.port : '';
|
||||
path += location.pathname;
|
||||
path += location.search ? location.search : '';
|
||||
path += this.hash.make ({
|
||||
'tpv_status': status,
|
||||
'tpv_order': order
|
||||
}, true);
|
||||
|
||||
return path;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -5,40 +5,15 @@ Vn.Orders = new Class
|
|||
|
||||
,activate: function ()
|
||||
{
|
||||
this.$('balance-amount').conditionalFunc = this.balanceConditionalFunc;
|
||||
|
||||
this.payPopup = new Htk.Popup ();
|
||||
this.payPopup.setChildNode (this.$('balance-popup'));
|
||||
|
||||
// Ends the transaction
|
||||
|
||||
var tpvStatus = this.hash.get ('tpv_status');
|
||||
|
||||
if (tpvStatus)
|
||||
{
|
||||
var batch = new Sql.Batch ();
|
||||
batch.addValue ('transaction', this.hash.get ('tpv_order'));
|
||||
batch.addValue ('status', tpvStatus);
|
||||
|
||||
var query = 'CALL transaction_end (#transaction, #status)';
|
||||
|
||||
this.conn.execQuery (query,
|
||||
this.onTransactionEnd.bind (this), batch);
|
||||
}
|
||||
|
||||
this.tpv = new Vn.Tpv (this.conn, this.hash);
|
||||
}
|
||||
|
||||
,onStartClick: function ()
|
||||
,onBasketClick: function ()
|
||||
{
|
||||
Vn.Cookie.unset ('order');
|
||||
this.hash.set ({'form': 'ecomerce/checkout'});
|
||||
}
|
||||
|
||||
,onContinueClick: function (column, orderId)
|
||||
{
|
||||
this.hash.set ({
|
||||
'form': 'ecomerce/basket',
|
||||
'order': orderId
|
||||
});
|
||||
this.hash.set ({'form': 'ecomerce/basket'});
|
||||
}
|
||||
|
||||
,onShowClick: function (column, ticketId)
|
||||
|
@ -84,92 +59,14 @@ Vn.Orders = new Class
|
|||
|
||||
amount = amount <= 0 ? null : amount;
|
||||
|
||||
this.pay (amount, 40000, company);
|
||||
}
|
||||
|
||||
,onTicketPayClick: function (column, value, row)
|
||||
{
|
||||
var model = this.$('tickets');
|
||||
var company = model.get (row, 'company_id');
|
||||
var total = model.get (row, 'total');
|
||||
this.pay (total, total, company);
|
||||
}
|
||||
|
||||
,pay: function (defaultAmount, maxAmount, company)
|
||||
{
|
||||
var defaultAmountStr = '';
|
||||
|
||||
if (defaultAmount !== null)
|
||||
defaultAmountStr = Vn.Value.format (defaultAmount, '%.2d');
|
||||
if (amount !== null)
|
||||
defaultAmountStr = Vn.Value.format (amount, '%.2d');
|
||||
|
||||
var amount = parseFloat (prompt (_('AmountToPay:'), defaultAmountStr));
|
||||
|
||||
if (amount > 0 && (maxAmount === null || amount <= maxAmount))
|
||||
{
|
||||
var query = 'CALL transaction_start (#company, #amount)';
|
||||
|
||||
var batch = new Sql.Batch ();
|
||||
batch.addValue ('company', company);
|
||||
batch.addValue ('amount', parseInt (amount * 100));
|
||||
|
||||
this.conn.execQuery (query,
|
||||
this.onTransactionStart.bind (this), batch);
|
||||
}
|
||||
else if (!isNaN (amount))
|
||||
(new Htk.Toast ()).showError (_('AmountError'));
|
||||
}
|
||||
|
||||
,getTpvUrl: function (status, order)
|
||||
{
|
||||
var path = location.protocol +'//'+ location.host;
|
||||
path += location.port ? ':'+ location.port : '';
|
||||
path += location.pathname;
|
||||
path += location.search ? location.search : '';
|
||||
path += this.hash.make ({
|
||||
'tpv_status': status,
|
||||
'tpv_order': order
|
||||
}, true);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
,onTransactionStart: function (resultSet)
|
||||
{
|
||||
var res = resultSet.fetchResult ();
|
||||
|
||||
if (res && res.next ())
|
||||
{
|
||||
var form = this.$('tpv-form');
|
||||
form.action = res.get ('url');
|
||||
|
||||
var transactionId = res.get ('ds_order');
|
||||
form['Ds_Merchant_UrlOK'].value = this.getTpvUrl ('ok', transactionId);
|
||||
form['Ds_Merchant_UrlKO'].value = this.getTpvUrl ('ko', transactionId);
|
||||
|
||||
var fieldsMap =
|
||||
{
|
||||
'Ds_Merchant_Amount': 'amount'
|
||||
,'Ds_Merchant_Order': 'ds_order'
|
||||
,'Ds_Merchant_MerchantCode': 'id'
|
||||
,'Ds_Merchant_Currency': 'currency'
|
||||
,'Ds_Merchant_TransactionType': 'transaction_type'
|
||||
,'Ds_Merchant_Terminal': 'terminal'
|
||||
,'Ds_Merchant_MerchantURL': 'merchant_url'
|
||||
,'Ds_Merchant_MerchantSignature': 'signature'
|
||||
};
|
||||
|
||||
for (var field in fieldsMap)
|
||||
form[field].value = res.get (fieldsMap[field]);
|
||||
|
||||
form.submit ();
|
||||
}
|
||||
else
|
||||
alert (_('PayError'));
|
||||
}
|
||||
|
||||
,onTransactionEnd: function ()
|
||||
{
|
||||
this.$('tickets').refresh ();
|
||||
this.tpv.pay (amount, company);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
{
|
||||
height: 5em;
|
||||
}
|
||||
.orders .confirmed
|
||||
{
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
/* Info box */
|
||||
|
||||
|
|
|
@ -1,40 +1,12 @@
|
|||
<vn>
|
||||
<div id="form" class="orders">
|
||||
<div class="box">
|
||||
<div class="header">
|
||||
<h1><t>OpenOrders</t></h1>
|
||||
<div class="action-bar">
|
||||
<button on-click="onStartClick">
|
||||
<img src="image/dark/order.svg" alt=""/>
|
||||
<t>StartOrder</t>
|
||||
</button>
|
||||
</div>
|
||||
<div class="clear"/>
|
||||
</div>
|
||||
<div>
|
||||
<htk-grid show-header="false">
|
||||
<db-model updatable="true">
|
||||
SELECT o.id, date_send, Agencia
|
||||
FROM order_view o
|
||||
LEFT JOIN vn2008.Agencias a ON o.type_id = a.Id_Agencia
|
||||
</db-model>
|
||||
<htk-column-text column="id"/>
|
||||
<htk-column-date column="date_send" format="%A, %e of %B"/>
|
||||
<htk-column-button
|
||||
column="id"
|
||||
image="image/edit.svg"
|
||||
tip="_ContinueOrder"
|
||||
on-clicked="onContinueClick"/>
|
||||
</htk-grid>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box confirmed">
|
||||
<div class="header">
|
||||
<h1><t>LastOrders</t></h1>
|
||||
<div class="action-bar">
|
||||
<div id="balance">
|
||||
<t>PendingBalance:</t>
|
||||
<htk-label format="%.2d€" id="balance-amount">
|
||||
<htk-label format="%.2d€" conditional-func="balanceConditionalFunc">
|
||||
<db-calc-sum model="balance" column-name="amount"/>
|
||||
</htk-label>
|
||||
<img src="image/dark/info.svg" title="_PaymentInfo" class="balance-info" alt="Info"/>
|
||||
|
@ -42,6 +14,10 @@
|
|||
<button id="pay-button" title="_MakePayment" on-click="onPayButtonClick">
|
||||
<img src="image/dark/pay.svg" alt="_MakePayment"/>
|
||||
</button>
|
||||
<button on-click="onBasketClick" title="_ShoppingBasket">
|
||||
<img src="image/dark/basket.svg" alt=""/>
|
||||
<t>Basket</t>
|
||||
</button>
|
||||
</div>
|
||||
<div class="clear"/>
|
||||
</div>
|
||||
|
|
|
@ -48,6 +48,7 @@ Db.Iterator = new Class
|
|||
,iterChanged: function ()
|
||||
{
|
||||
this.signalEmit ('iter-changed');
|
||||
this.signalEmit ('iter-changed-after');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,7 +50,7 @@ Db.Model.implement
|
|||
,set: function (x)
|
||||
{
|
||||
this._conn = x;
|
||||
this.refresh ();
|
||||
this._autoLoad ();
|
||||
}
|
||||
,get: function ()
|
||||
{
|
||||
|
@ -80,8 +80,8 @@ Db.Model.implement
|
|||
type: Sql.Batch
|
||||
,set: function (x)
|
||||
{
|
||||
this.link ({_batch: x}, {'changed': this.refresh});
|
||||
this.refresh ();
|
||||
this.link ({_batch: x}, {'changed': this._autoLoad});
|
||||
this._autoLoad ();
|
||||
}
|
||||
,get: function ()
|
||||
{
|
||||
|
@ -97,7 +97,7 @@ Db.Model.implement
|
|||
,set: function (x)
|
||||
{
|
||||
this._stmt = x;
|
||||
this.refresh ();
|
||||
this._autoLoad ();
|
||||
}
|
||||
,get: function ()
|
||||
{
|
||||
|
@ -188,6 +188,22 @@ Db.Model.implement
|
|||
{
|
||||
return this._status == Db.Model.Status.READY;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Update mode.
|
||||
**/
|
||||
mode:
|
||||
{
|
||||
enumType: Db.Model.Mode
|
||||
,value: Db.Model.Mode.ON_CHANGE
|
||||
},
|
||||
/**
|
||||
* Wether to execute the model query automatically.
|
||||
**/
|
||||
autoLoad:
|
||||
{
|
||||
type: Boolean
|
||||
,value: true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +223,6 @@ Db.Model.implement
|
|||
,indexes: []
|
||||
|
||||
,requestedUpdatable: false
|
||||
,mode: Db.Model.Mode.ON_CHANGE
|
||||
,operations: null
|
||||
,operationsMap: null
|
||||
,defaults: []
|
||||
|
@ -229,6 +244,12 @@ Db.Model.implement
|
|||
if (query)
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
,_autoLoad: function ()
|
||||
{
|
||||
if (this.autoLoad)
|
||||
this.refresh ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the model data reexecuting the query on the database.
|
||||
|
@ -633,7 +654,10 @@ Db.Model.implement
|
|||
var ops = this.operations;
|
||||
|
||||
if (ops.length === 0)
|
||||
{
|
||||
this.signalEmit ('operations-done');
|
||||
return;
|
||||
}
|
||||
|
||||
var stmts = new Sql.MultiStmt ();
|
||||
|
||||
|
@ -679,7 +703,7 @@ Db.Model.implement
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var query = new Sql.String ({query: 'COMMIT'});
|
||||
stmts.addStmt (query);
|
||||
|
||||
|
@ -773,7 +797,7 @@ Db.Model.implement
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var isOperation = false;
|
||||
|
||||
resultSet.fetchResult ();
|
||||
|
@ -833,7 +857,7 @@ Db.Model.implement
|
|||
|
||||
resultSet.fetchResult ();
|
||||
|
||||
if (isOperation)
|
||||
// if (isOperation)
|
||||
this.signalEmit ('operations-done');
|
||||
}
|
||||
|
||||
|
|
|
@ -115,9 +115,6 @@ Htk.Select = new Class
|
|||
{
|
||||
var model = this._model;
|
||||
this.signalEmit ('status-changed');
|
||||
|
||||
if (model.status == Db.Model.Status.LOADING)
|
||||
return;
|
||||
|
||||
Vn.Node.removeChilds (this.node);
|
||||
|
||||
|
@ -136,6 +133,8 @@ Htk.Select = new Class
|
|||
}
|
||||
case Db.Model.Status.ERROR:
|
||||
this.addOption (null, _('Error'));
|
||||
case Db.Model.Status.LOADING:
|
||||
this.addOption (null, _('Loading...'));
|
||||
default:
|
||||
this.setRow (-1);
|
||||
}
|
||||
|
|
|
@ -72,6 +72,11 @@ Htk.Repeater = new Class
|
|||
this.onModelChange ();
|
||||
}
|
||||
|
||||
,getChild: function (index)
|
||||
{
|
||||
return this.node.childNodes[index];
|
||||
}
|
||||
|
||||
,buildBox: function (index)
|
||||
{
|
||||
var builder = new Vn.Builder ();
|
||||
|
|
|
@ -285,6 +285,9 @@ Vn.Builder = new Class
|
|||
|
||||
if (value !== undefined)
|
||||
c.object[propName] = value;
|
||||
else
|
||||
console.warn ('Vn.Builder: Empty attribute \'%s\' on tag \'%s\'',
|
||||
attribute, c.node.tagName);
|
||||
}
|
||||
|
||||
,setParent: function (parentBuilder)
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
,"DateExit": "Fecha de salida"
|
||||
,"Warehouse": "Almacén"
|
||||
,"OrderTotal": "Total"
|
||||
,"VATNotIncluded": "(IVA y transporte no incluídos)"
|
||||
|
||||
,"Amount": "Cantidad"
|
||||
,"Pack": "Pack"
|
||||
|
@ -24,4 +23,6 @@
|
|||
,"Price": "Precio"
|
||||
,"Disc": "Desc"
|
||||
,"Subtotal": "Subtotal"
|
||||
|
||||
,"OrderItemsUpdated": "Su pedido lleva demasiado tiempo abierto y ha sido actualizado, los precios o cantidades de sus artículos pueden haber cambiado."
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
,"Agency": "Agencia"
|
||||
,"Warehouse": "Almacén"
|
||||
,"Confirm": "Confirmar"
|
||||
|
||||
,"ErrorCreatingOrder": "Error al crear el pedido"
|
||||
|
||||
,"OrderStarted": "Pedido empezado"
|
||||
,"OrderUpdated": "Pedido actualizado"
|
||||
,"RememberReconfiguringImpact": "Recuerde que si vuelve a configurar el pedido los precios o cantidades de sus artículos podrían cambiar."
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
,"Company": "Empresa"
|
||||
,"Pending": "Pendiente"
|
||||
,"Pay": "Pagar"
|
||||
,"Basket": "Cesta"
|
||||
,"ShoppingBasket": "Cesta de la compra"
|
||||
|
||||
,"SeeOrder": "Mostrar detalle del pedido"
|
||||
,"TicketNumber": "Nº ticket"
|
||||
|
|
|
@ -10,6 +10,7 @@ Vn.Locale.add
|
|||
,"OfThe": "del"
|
||||
,"Remove": "Borrar"
|
||||
,"Loading": "Cargando"
|
||||
,"Loading...": "Cargando..."
|
||||
,"ReallyDelete": "¿Realmente desea borrar la línea?"
|
||||
,"EmptyList": "Lista vacía"
|
||||
,"NoData": "Sin datos"
|
||||
|
@ -18,7 +19,7 @@ Vn.Locale.add
|
|||
,"Image": "Imagen"
|
||||
,"File": "Archivo"
|
||||
,"FileName": "Nombre"
|
||||
,"UpdateImage": "Añadir / Actualizar Imagen"
|
||||
,"UpdateImage": "Añadir o actualizar imagen"
|
||||
,"UploadFile": "Subir archivo"
|
||||
,"ImageAdded": "Imagen añadida correctamente"
|
||||
,"Close": "Cerrar"
|
||||
|
|
|
@ -7,6 +7,7 @@ require_once ('js/htk/main.php');
|
|||
|
||||
Js::includeFile ('pages/web/web.js');
|
||||
Js::includeFile ('pages/web/module.js');
|
||||
Js::includeFile ('pages/web/tpv.js');
|
||||
|
||||
Js::includeCss ('global/style.css');
|
||||
Js::includeCss ('pages/web/style.css');
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
Vn.Tpv = new Class
|
||||
({
|
||||
initialize: function (conn, hash)
|
||||
{
|
||||
this.conn = conn;
|
||||
this.hash = hash;
|
||||
|
||||
var tpvStatus = this.hash.get ('tpv_status');
|
||||
|
||||
if (tpvStatus)
|
||||
{
|
||||
var batch = new Sql.Batch ();
|
||||
batch.addValue ('transaction', this.hash.get ('tpv_order'));
|
||||
batch.addValue ('status', tpvStatus);
|
||||
|
||||
var query = 'CALL transaction_end (#transaction, #status)';
|
||||
|
||||
this.conn.execQuery (query, null, batch);
|
||||
}
|
||||
}
|
||||
|
||||
,pay: function (amount, company)
|
||||
{
|
||||
if (amount > 0)
|
||||
{
|
||||
var query = 'CALL transaction_start (#company, #amount)';
|
||||
|
||||
var batch = new Sql.Batch ();
|
||||
batch.addValue ('company', company);
|
||||
batch.addValue ('amount', parseInt (amount * 100));
|
||||
|
||||
this.conn.execQuery (query,
|
||||
this.onTransactionStart.bind (this), batch);
|
||||
}
|
||||
else if (!isNaN (amount))
|
||||
(new Htk.Toast ()).showError (_('AmountError'));
|
||||
}
|
||||
|
||||
,onTransactionStart: function (resultSet)
|
||||
{
|
||||
var res = resultSet.fetchResult ();
|
||||
|
||||
if (res && res.next ())
|
||||
{
|
||||
var form = document.createElement ('form');
|
||||
form.method = 'post';
|
||||
form.action = res.get ('url');
|
||||
document.body.appendChild (form);
|
||||
|
||||
var fieldsMap =
|
||||
{
|
||||
'Ds_Merchant_Amount': 'amount'
|
||||
,'Ds_Merchant_Order': 'ds_order'
|
||||
,'Ds_Merchant_MerchantCode': 'id'
|
||||
,'Ds_Merchant_Currency': 'currency'
|
||||
,'Ds_Merchant_TransactionType': 'transaction_type'
|
||||
,'Ds_Merchant_Terminal': 'terminal'
|
||||
,'Ds_Merchant_MerchantURL': 'merchant_url'
|
||||
,'Ds_Merchant_MerchantSignature': 'signature'
|
||||
,'Ds_Merchant_UrlOK': null
|
||||
,'Ds_Merchant_UrlKO': null
|
||||
};
|
||||
|
||||
for (var field in fieldsMap)
|
||||
{
|
||||
var input = document.createElement ('input');
|
||||
input.type = 'hidden';
|
||||
input.name = field;
|
||||
form.appendChild (input);
|
||||
|
||||
if (fieldsMap[field])
|
||||
input.value = res.get (fieldsMap[field]);
|
||||
}
|
||||
|
||||
var transactionId = res.get ('ds_order');
|
||||
form['Ds_Merchant_UrlOK'].value = this.makeUrl ('ok', transactionId);
|
||||
form['Ds_Merchant_UrlKO'].value = this.makeUrl ('ko', transactionId);
|
||||
|
||||
form.submit ();
|
||||
}
|
||||
else
|
||||
alert (_('PayError'));
|
||||
}
|
||||
|
||||
,makeUrl: function (status, order)
|
||||
{
|
||||
var path = location.protocol +'//'+ location.host;
|
||||
path += location.port ? ':'+ location.port : '';
|
||||
path += location.pathname;
|
||||
path += location.search ? location.search : '';
|
||||
path += this.hash.make ({
|
||||
'tpv_status': status,
|
||||
'tpv_order': order
|
||||
}, true);
|
||||
|
||||
return path;
|
||||
}
|
||||
});
|
||||
|
|
@ -92,6 +92,7 @@ class Web
|
|||
,$conf['db']['user']
|
||||
,base64_decode ($conf['db']['pass'])
|
||||
,$conf['db']['schema']
|
||||
,$conf['db']['port']
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -138,6 +139,7 @@ class Web
|
|||
,Auth::getUser ()
|
||||
,Auth::getPassword ()
|
||||
,$conf['db']['schema']
|
||||
,$conf['db']['port']
|
||||
);
|
||||
self::$conn->query ('CALL user_session_start (#)',
|
||||
[session_id ()]);
|
||||
|
|
Loading…
Reference in New Issue