Initial commit
This commit is contained in:
commit
809fb268cc
|
@ -0,0 +1,14 @@
|
|||
Copyright (C) 2013 Zikzakmedia SL.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
@ -0,0 +1,25 @@
|
|||
Installing Flask OpenERP Stock Cart
|
||||
===================================
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
* Flask (https://pypi.python.org/pypi/Flask)
|
||||
* Flask-Babel (https://pypi.python.org/pypi/Flask-Babel)
|
||||
* Flask-WTF (https://pypi.python.org/pypi/Flask-WTF)
|
||||
* ERPPeek (https://pypi.python.org/pypi/ERPpeek)
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
config.ini
|
||||
|
||||
* APP NAME
|
||||
|
||||
config.cfg
|
||||
|
||||
* Debug
|
||||
* Template
|
||||
* Language
|
||||
* Payments
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
Flask OpenERP Stock Cart
|
||||
========================
|
||||
|
||||
Flask OpenERP Stock Cart is a Flask App to management stock pickings in warehouse.
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
See INSTALL
|
||||
|
||||
OpenERP modules
|
||||
---------------
|
||||
|
||||
* Stock
|
||||
* Stock Cart
|
||||
* Product Trademark
|
||||
* Nan Stock Scanner
|
||||
|
||||
OpenERP Configuration
|
||||
---------------------
|
||||
|
||||
Edit config.ini and add OpenERP connection:
|
||||
|
||||
OPENERP_SERVER = 'http://localhost:8069'
|
||||
OPENERP_DATABASE = 'database'
|
||||
|
||||
Username and password is from login form.
|
||||
|
||||
Check username have permissions to read and write in models:
|
||||
|
||||
* stock.picking
|
||||
* stock.cart
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
For more information or if you encounter any problems with this module,
|
||||
please contact the programmers at
|
||||
|
||||
Zikzakmedia
|
||||
--------------
|
||||
website: http://www.zikzakmedia.com/
|
||||
email: zikzak@zikzakmedia.com
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
See LICENSE
|
||||
|
||||
Copyright
|
||||
---------
|
||||
|
||||
See COPYRIGHT
|
|
@ -0,0 +1,271 @@
|
|||
#This file is part openerp-stock-cart app for Flask.
|
||||
#The COPYRIGHT file at the top level of this repository contains
|
||||
#the full copyright notices and license terms.
|
||||
import os
|
||||
import ConfigParser
|
||||
import erppeek
|
||||
import bz2
|
||||
import socket
|
||||
from functools import wraps
|
||||
|
||||
from flask import Flask, render_template, request, jsonify, abort, session, redirect, url_for, flash
|
||||
from flask.ext.babel import Babel, gettext as _
|
||||
|
||||
from apphelp import get_description
|
||||
from form import *
|
||||
from defaultfilters import *
|
||||
|
||||
|
||||
def get_config():
|
||||
'''Get values from cfg file'''
|
||||
conf_file = '%s/config.ini' % os.path.dirname(os.path.realpath(__file__))
|
||||
config = ConfigParser.ConfigParser()
|
||||
config.read(conf_file)
|
||||
|
||||
results = {}
|
||||
for section in config.sections():
|
||||
results[section] = {}
|
||||
for option in config.options(section):
|
||||
results[section][option] = config.get(section, option)
|
||||
return results
|
||||
|
||||
def create_app(config=None):
|
||||
'''Create Flask APP'''
|
||||
cfg = get_config()
|
||||
app_name = cfg['flask']['app_name']
|
||||
app = Flask(app_name)
|
||||
app.config.from_pyfile(config)
|
||||
|
||||
return app
|
||||
|
||||
def get_template(tpl):
|
||||
'''Get template'''
|
||||
return "%s/%s" % (app.config.get('TEMPLATE'), tpl)
|
||||
|
||||
def parse_setup(filename):
|
||||
globalsdict = {} # put predefined things here
|
||||
localsdict = {} # will be populated by executed script
|
||||
execfile(filename, globalsdict, localsdict)
|
||||
return localsdict
|
||||
|
||||
def get_lang():
|
||||
return app.config.get('LANGUAGE')
|
||||
|
||||
def erp_connect():
|
||||
'''OpenERP Connection'''
|
||||
server = app.config.get('OPENERP_SERVER')
|
||||
database = app.config.get('OPENERP_DATABASE')
|
||||
username = session['username']
|
||||
password = bz2.decompress(session['password'])
|
||||
try:
|
||||
Client = erppeek.Client(server, db=database, user=username, password=password)
|
||||
except socket.error:
|
||||
flash(_("Can't connect to ERP server. Check network-ports or ERP server was running."))
|
||||
abort(500)
|
||||
except:
|
||||
abort(500)
|
||||
return Client
|
||||
|
||||
def login_required(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
logged = session.get('logged_in', None)
|
||||
if not logged:
|
||||
return redirect(url_for('login'))
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
|
||||
conf_file = '%s/config.cfg' % os.path.dirname(os.path.realpath(__file__))
|
||||
app = create_app(conf_file)
|
||||
app.config['BABEL_DEFAULT_LOCALE'] = get_lang()
|
||||
app.root_path = os.path.dirname(os.path.abspath(__file__))
|
||||
babel = Babel(app)
|
||||
|
||||
# OpenERP models - access
|
||||
MODELS_ACCESS = ({
|
||||
'stock.picking': 'write',
|
||||
'stock.cart': 'read',
|
||||
})
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return render_template(get_template('404.html')), 404
|
||||
|
||||
@app.errorhandler(500)
|
||||
def server_error(e):
|
||||
return render_template(get_template('500.html')), 500
|
||||
|
||||
@app.route('/')
|
||||
@login_required
|
||||
def index():
|
||||
'''Dashboard'''
|
||||
cart = session.get('cart', None)
|
||||
if not cart:
|
||||
return redirect(url_for('cart'))
|
||||
|
||||
return render_template(get_template('index.html'))
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
'''Login'''
|
||||
form = LoginForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
username = request.form.get('username')
|
||||
password = bz2.compress(request.form.get('password'))
|
||||
session['username'] = username
|
||||
session['password'] = password
|
||||
|
||||
Client = erp_connect()
|
||||
login = Client.login(username, bz2.decompress(password), app.config.get('OPENERP_DATABASE'))
|
||||
if login:
|
||||
access = True
|
||||
for key, value in MODELS_ACCESS.iteritems():
|
||||
if not Client.access(key, mode=value):
|
||||
access = False
|
||||
flash(_('Error: Not access in %(key)s - %(value)s' % { 'key': key, 'value': value} ))
|
||||
if access:
|
||||
session['logged_in'] = True
|
||||
flash(_('You were logged in.'))
|
||||
return redirect(url_for('index'))
|
||||
else:
|
||||
flash(_('Error: Invalid username or password'))
|
||||
|
||||
return render_template(get_template('login.html'), form=form)
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
'''Logout App'''
|
||||
Client = erp_connect()
|
||||
|
||||
# Remove all stock.cart by user
|
||||
StockCart = Client.model('stock.cart')
|
||||
user_id = Client.search('res.users',[
|
||||
('login', '=', session.get('username')),
|
||||
])[0]
|
||||
carts = Client.search('stock.cart',[
|
||||
('user_id', '=', user_id),
|
||||
])
|
||||
for cart in carts:
|
||||
c = StockCart.get(cart)
|
||||
c.write({'user_id': None})
|
||||
|
||||
# Remove all sessions
|
||||
session.pop('logged_in', None)
|
||||
|
||||
session.pop('username', None)
|
||||
session.pop('password', None)
|
||||
session.pop('cart', None)
|
||||
session.pop('cart_name', None)
|
||||
|
||||
flash(_('You were logged out.'))
|
||||
return redirect(url_for('login'))
|
||||
|
||||
@app.route('/cart', methods=["GET"])
|
||||
@login_required
|
||||
def cart():
|
||||
'''Select a stock cart by user'''
|
||||
Client = erp_connect()
|
||||
StockCart = Client.model('stock.cart')
|
||||
|
||||
'''Drop currenty cart by user'''
|
||||
if session.get('cart'):
|
||||
cart_old = StockCart.get(int(session.get('cart')))
|
||||
cart_old.write({'user_id': None})
|
||||
session.pop('cart', None)
|
||||
session.pop('cart_name', None)
|
||||
|
||||
'''Get cart id and add who working in stock.cart'''
|
||||
if request.method == 'GET':
|
||||
cart = request.args.get('cart', None)
|
||||
order = request.args.get('order', None)
|
||||
|
||||
if cart:
|
||||
try:
|
||||
# Get Cart object from request.get
|
||||
id = int(cart)
|
||||
cart = StockCart.get(id)
|
||||
|
||||
if not cart.user_id and cart.active:
|
||||
#get user id
|
||||
user_id = Client.search('res.users',[
|
||||
('login', '=', session.get('username')),
|
||||
])[0]
|
||||
|
||||
# Add new session values and log in stock.cart
|
||||
session['cart'] = cart.id
|
||||
session['cart_name'] = cart.name
|
||||
session['cart_rows'] = cart.rows
|
||||
session['cart_columns'] = cart.columns
|
||||
|
||||
cart.write({'user_id': user_id})
|
||||
return redirect(url_for('index'))
|
||||
else:
|
||||
if cart.user_id:
|
||||
flash(_(u'Cart %(name)s is working by user %(user)s.', name=cart.name, user=cart.user_id))
|
||||
else:
|
||||
flash(_(u'Not find some cart by %(id)s.', id=cart))
|
||||
except:
|
||||
flash(_('Error: Cart ID not valid or empty'))
|
||||
|
||||
if order:
|
||||
flash(_(u'Order products by: %(order)s.', order=order))
|
||||
session['order'] = order
|
||||
|
||||
carts = StockCart.browse([('active', '=', True)])
|
||||
return render_template(get_template('cart.html'), carts=carts)
|
||||
|
||||
@app.route('/picking')
|
||||
@login_required
|
||||
def picking():
|
||||
'''Get all pickings and get info to make pickings'''
|
||||
cart = session.get('cart', None)
|
||||
order = session.get('order', None)
|
||||
if not cart:
|
||||
return redirect(url_for('cart'))
|
||||
|
||||
Client = erp_connect()
|
||||
products, picking_grid = Client.execute('stock.picking', 'get_products_to_cart', cart, order)
|
||||
|
||||
return render_template(get_template('picking.html'), products=products, grid=picking_grid)
|
||||
|
||||
@app.route('/basket', methods=['PUT', 'POST'])
|
||||
def basket():
|
||||
'''
|
||||
Process values from form basket
|
||||
name: picking-product ID's
|
||||
value: qty to add in basket
|
||||
'''
|
||||
cart = session.get('cart', None)
|
||||
Client = erp_connect()
|
||||
|
||||
values = []
|
||||
result = True
|
||||
for data in request.json:
|
||||
|
||||
try:
|
||||
move = int(data['name'])
|
||||
qty = int(data['value'])
|
||||
except:
|
||||
result = False
|
||||
|
||||
values.append({
|
||||
'move': move,
|
||||
'qty': qty,
|
||||
})
|
||||
|
||||
if result:
|
||||
Client.execute('stock.picking', 'set_products_to_cart', cart, values)
|
||||
|
||||
return jsonify(result=result)
|
||||
|
||||
@app.route('/help')
|
||||
def help():
|
||||
'''Help - Documentation'''
|
||||
lang = get_lang()
|
||||
description = get_description(lang)
|
||||
return render_template(get_template('help.html'), content=description)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
|
@ -0,0 +1,64 @@
|
|||
#This file is part openerp-stock-cart app for Flask.
|
||||
#The COPYRIGHT file at the top level of this repository contains
|
||||
#the full copyright notices and license terms.
|
||||
import os
|
||||
import docutils.core
|
||||
|
||||
def get_description(lang):
|
||||
'''Get Description module from doc rst'''
|
||||
description = ''
|
||||
|
||||
doc_path = 'doc/%s/index.rst' % (lang)
|
||||
if os.path.exists(doc_path):
|
||||
return read_rst(doc_path)
|
||||
|
||||
doc_path = 'doc/index.rst'
|
||||
if os.path.exists(doc_path):
|
||||
return read_rst(doc_path)
|
||||
return description
|
||||
|
||||
def read_rst(doc_path):
|
||||
f = open(doc_path, "r")
|
||||
description = f.read()
|
||||
|
||||
def rst2html(source, source_path=None, source_class=docutils.io.StringInput,
|
||||
destination_path=None, reader=None, reader_name='standalone',
|
||||
parser=None, parser_name='restructuredtext', writer=None,
|
||||
writer_name='html', settings=None, settings_spec=None,
|
||||
settings_overrides=None, config_section=None,
|
||||
enable_exit_status=None):
|
||||
"""
|
||||
Set up & run a `Publisher`, and return a dictionary of document parts.
|
||||
Dictionary keys are the names of parts, and values are Unicode strings;
|
||||
encoding is up to the client. For programmatic use with string I/O.
|
||||
|
||||
For encoded string input, be sure to set the 'input_encoding' setting to
|
||||
the desired encoding. Set it to 'unicode' for unencoded Unicode string
|
||||
input. Here's how::
|
||||
|
||||
publish_parts(..., settings_overrides={'input_encoding': 'unicode'})
|
||||
|
||||
Parameters: see `publish_programmatically`.
|
||||
"""
|
||||
output, pub = docutils.core.publish_programmatically(
|
||||
source=source, source_path=source_path, source_class=source_class,
|
||||
destination_class=docutils.io.StringOutput,
|
||||
destination=None, destination_path=destination_path,
|
||||
reader=reader, reader_name=reader_name,
|
||||
parser=parser, parser_name=parser_name,
|
||||
writer=writer, writer_name=writer_name,
|
||||
settings=settings, settings_spec=settings_spec,
|
||||
settings_overrides=settings_overrides,
|
||||
config_section=config_section,
|
||||
enable_exit_status=enable_exit_status)
|
||||
return pub.writer.parts['fragment'], pub.document.reporter.max_level, pub.settings.record_dependencies
|
||||
|
||||
output, error_level, deps = rst2html(
|
||||
description, settings_overrides={
|
||||
'initial_header_level': 2,
|
||||
'record_dependencies': True,
|
||||
'stylesheet_path': None,
|
||||
'link_stylesheet': True,
|
||||
'syntax_highlight': 'short',
|
||||
})
|
||||
return output
|
|
@ -0,0 +1,3 @@
|
|||
[python: **.py]
|
||||
[jinja2: **/templates/**.html]
|
||||
extensions=jinja2.ext.autoescape,jinja2.ext.with_
|
|
@ -0,0 +1,13 @@
|
|||
DEBUG = True
|
||||
DEBUG_LOG = 'logs/debug.log'
|
||||
ERROR_LOG = 'logs/error.log'
|
||||
|
||||
ADMINS = ('user@domain.com',)
|
||||
TITLE = 'OpenERP Stock Cart'
|
||||
TEMPLATE = 'default'
|
||||
LANGUAGE = 'es'
|
||||
AUTHOR = 'Zikzakmedia'
|
||||
SECRET_KEY = 'C5G94WB6BVRPHTO85RGI2Y6TM6HYY0P'
|
||||
|
||||
OPENERP_SERVER = 'http://localhost:8069'
|
||||
OPENERP_DATABASE = 'databasename'
|
|
@ -0,0 +1,2 @@
|
|||
[flask]
|
||||
APP_NAME = 'openerpstockcart'
|
|
@ -0,0 +1,35 @@
|
|||
#This file is part openerp-stock-cart app for Flask.
|
||||
#The COPYRIGHT file at the top level of this repository contains
|
||||
#the full copyright notices and license terms.
|
||||
import jinja2
|
||||
|
||||
def floatwithoutdecimal(text):
|
||||
"""
|
||||
Convert a float to integer.
|
||||
|
||||
* num1 = 34.23234
|
||||
* num2 = 34.00000
|
||||
* num3 = 34.26000
|
||||
* {{ num1|floatformat }} displays "34"
|
||||
* {{ num2|floatformat }} displays "34"
|
||||
* {{ num3|floatformat }} displays "34"
|
||||
"""
|
||||
|
||||
try:
|
||||
float(text)
|
||||
except:
|
||||
return ''
|
||||
|
||||
return '{0:g}'.format(float(text))
|
||||
jinja2.filters.FILTERS['floatwithoutdecimal'] = floatwithoutdecimal
|
||||
|
||||
def pickingname(pickings, arg):
|
||||
"""
|
||||
Get picking name from dict.
|
||||
|
||||
* pickings = {'1': 'P1230', '2': 'P1231'}
|
||||
"""
|
||||
if not arg:
|
||||
return None
|
||||
return pickings[str(arg)]
|
||||
jinja2.filters.FILTERS['pickingname'] = pickingname
|
|
@ -0,0 +1,26 @@
|
|||
------------------
|
||||
OpenERP Stock Cart
|
||||
------------------
|
||||
|
||||
Esta herramienta le permitirá gestionar los productos y albaranes de vuestro almacén.
|
||||
|
||||
* Seleccione que carrito va a usar en sus preferencias. Sólo podrá usar un carrito
|
||||
a la vez y sólo podrá seleccionar los carritos que estén disponibles.
|
||||
* Si un usuario quiere abandonar o cambiar de carrito, acceda a la sección de **Carros**
|
||||
para liberar el carro o cambiar.
|
||||
|
||||
Cajas del carro
|
||||
---------------
|
||||
|
||||
Un carro dispone de varias cajas. Cada caja del carro equivale a un albarán. En
|
||||
cada caja deberá poner los productos que tiene cada albarán.
|
||||
|
||||
Proceso del carro
|
||||
-----------------
|
||||
|
||||
Cuando inicie el proceso de recogida de productos, se le mostrará un listado de
|
||||
productos y el número de productos a recoger. Por cada producto, sabrá cuantas unidades
|
||||
debe dejar en cada caja del carro. Recuerde que cada caja del carro equivale a un albarán.
|
||||
|
||||
Una vez de vuelta al muelle de salida, deberá revisar que en cada caja del carro haya
|
||||
los productos correspondientes y ya podrá ejecutar el empaquetado y el etiquetaje.
|
|
@ -0,0 +1,6 @@
|
|||
------------------
|
||||
OpenERP Stock Cart
|
||||
------------------
|
||||
|
||||
Cart management warehouse. Select products by cart and make pickings when finish
|
||||
all process from products.
|
|
@ -0,0 +1,19 @@
|
|||
#This file is part openerp-sale-payment app for Flask.
|
||||
#The COPYRIGHT file at the top level of this repository contains
|
||||
#the full copyright notices and license terms.
|
||||
from flask.ext.wtf import Form
|
||||
from wtforms import TextField, PasswordField, validators
|
||||
|
||||
|
||||
class LoginForm(Form):
|
||||
username = TextField('Username', [validators.Required()])
|
||||
password = PasswordField('Password', [validators.Required()])
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
Form.__init__(self, *args, **kwargs)
|
||||
|
||||
def validate(self):
|
||||
rv = Form.validate(self)
|
||||
if not rv:
|
||||
return False
|
||||
return True
|
|
@ -0,0 +1,242 @@
|
|||
# Translations template for PROJECT.
|
||||
# Copyright (C) 2013 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2013-05-28 11:34+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 0.9.6\n"
|
||||
|
||||
#: app.py:64
|
||||
msgid ""
|
||||
"Can't connect to ERP server. Check network-ports or ERP server was "
|
||||
"running."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:128
|
||||
#, python-format
|
||||
msgid "Error: Not access in %(key)s - %(value)skey"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:131
|
||||
msgid "You were logged in."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:134
|
||||
msgid "Error: Invalid username or password"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:163
|
||||
msgid "You were logged out."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:207
|
||||
#, python-format
|
||||
msgid "Cart %(name)s is working by user %(user)s."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:209
|
||||
#, python-format
|
||||
msgid "Not find some cart by %(id)s."
|
||||
msgstr ""
|
||||
|
||||
#: app.py:211
|
||||
msgid "Error: Cart ID not valid or empty"
|
||||
msgstr ""
|
||||
|
||||
#: app.py:214
|
||||
#, python-format
|
||||
msgid "Order products by: %(order)s."
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/cart.html:2 templates/default/index.html:8
|
||||
#: templates/default/index.html:18 templates/default/nav.html:23
|
||||
#: templates/default/picking.html:2
|
||||
msgid "Select a cart"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/cart.html:7
|
||||
msgid "Order products by"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/cart.html:11
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/cart.html:12
|
||||
msgid "Baskets"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/cart.html:13
|
||||
msgid "User"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/cart.html:23
|
||||
msgid "Get this cart"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/help.html:9
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:2
|
||||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:8 templates/default/nav.html:23
|
||||
msgid "Change cart"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:9 templates/default/index.html:24
|
||||
#: templates/default/nav.html:13
|
||||
msgid "Process pickings"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:10 templates/default/nav.html:24
|
||||
msgid "Help"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:19
|
||||
msgid ""
|
||||
"Go to your preferences a select a cart do you work. Remember when not "
|
||||
"working in warehouse, do logout"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:19 templates/default/index.html:25
|
||||
msgid "Go"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:25
|
||||
msgid ""
|
||||
"When process pickings, select products in your warehouse and put in you "
|
||||
"backet cart."
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:30
|
||||
msgid "Make picking"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/index.html:31
|
||||
msgid ""
|
||||
"When finish selection products, return your picking area and make "
|
||||
"delivery package."
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/login.html:2 templates/default/login.html:47
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/login.html:14
|
||||
msgid "Add a user name"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/login.html:15
|
||||
msgid "Add a password"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/login.html:34
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/login.html:40
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/nav.html:17
|
||||
msgid "Welcome"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/nav.html:19
|
||||
msgid "Order by"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/nav.html:20
|
||||
msgid "Location"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/nav.html:21
|
||||
msgid "Manufacturer"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/nav.html:25
|
||||
msgid "Logout"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:11
|
||||
msgid "Code"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:12
|
||||
msgid "Product"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:13 templates/default/picking.html:52
|
||||
msgid "Qty"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:14
|
||||
msgid "Qty Available"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:15
|
||||
msgid "Rack"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:16
|
||||
msgid "Row"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:17
|
||||
msgid "Case"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:21
|
||||
msgid "There are not pickings to process"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:52
|
||||
msgid "Qty added in this basket "
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:62
|
||||
msgid "Process"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:68
|
||||
msgid "Grid Cart"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:81
|
||||
msgid "Send quantity products successfully"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:84
|
||||
msgid "Get more products/pickings to do"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:87
|
||||
msgid "Done"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:95
|
||||
msgid "Error!"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:98
|
||||
msgid "Qty are integer values? Review your cart and resend"
|
||||
msgstr ""
|
||||
|
||||
#: templates/default/picking.html:101
|
||||
msgid "Check"
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Flask-Babel>=0.8
|
||||
Flask-WTF>=0.8.3
|
||||
erppeek>=1.4.5
|
|
@ -0,0 +1,214 @@
|
|||
/*!
|
||||
* Bootstrap Modal
|
||||
*
|
||||
* Copyright Jordan Schroter
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
.modal-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* add a scroll bar to stop page from jerking around */
|
||||
.modal-open.page-overflow .page-container,
|
||||
.modal-open.page-overflow .page-container .navbar-fixed-top,
|
||||
.modal-open.page-overflow .page-container .navbar-fixed-bottom,
|
||||
.modal-open.page-overflow .modal-scrollable {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
@media (max-width: 979px) {
|
||||
.modal-open.page-overflow .page-container .navbar-fixed-top,
|
||||
.modal-open.page-overflow .page-container .navbar-fixed-bottom {
|
||||
overflow-y: visible;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.modal-scrollable {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.modal {
|
||||
outline: none;
|
||||
position: absolute;
|
||||
margin-top: 0;
|
||||
top: 50%;
|
||||
overflow: visible; /* allow content to popup out (i.e tooltips) */
|
||||
}
|
||||
|
||||
.modal.fade {
|
||||
top: -100%;
|
||||
-webkit-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out;
|
||||
-moz-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out;
|
||||
-o-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out;
|
||||
transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out;
|
||||
}
|
||||
|
||||
.modal.fade.in {
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
max-height: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.modal.modal-absolute {
|
||||
position: absolute;
|
||||
z-index: 950;
|
||||
}
|
||||
|
||||
.modal .loading-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.modal-backdrop.modal-absolute{
|
||||
position: absolute;
|
||||
z-index: 940;
|
||||
}
|
||||
|
||||
.modal-backdrop,
|
||||
.modal-backdrop.fade.in{
|
||||
opacity: 0.7;
|
||||
filter: alpha(opacity=70);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.modal.container {
|
||||
width: 940px;
|
||||
margin-left: -470px;
|
||||
}
|
||||
|
||||
/* Modal Overflow */
|
||||
|
||||
.modal-overflow.modal {
|
||||
top: 1%;
|
||||
}
|
||||
|
||||
.modal-overflow.modal.fade {
|
||||
top: -100%;
|
||||
}
|
||||
|
||||
.modal-overflow.modal.fade.in {
|
||||
top: 1%;
|
||||
}
|
||||
|
||||
.modal-overflow .modal-body {
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.modal.container {
|
||||
width: 1170px;
|
||||
margin-left: -585px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 979px) {
|
||||
.modal,
|
||||
.modal.container,
|
||||
.modal.modal-overflow {
|
||||
top: 1%;
|
||||
right: 1%;
|
||||
left: 1%;
|
||||
bottom: auto;
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.modal.fade.in,
|
||||
.modal.container.fade.in,
|
||||
.modal.modal-overflow.fade.in {
|
||||
top: 1%;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
.modal-body,
|
||||
.modal-overflow .modal-body {
|
||||
position: static;
|
||||
margin: 0;
|
||||
height: auto !important;
|
||||
max-height: none !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.modal-footer,
|
||||
.modal-overflow .modal-footer {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -12px 0 0 -12px;
|
||||
}
|
||||
|
||||
/*
|
||||
Animate.css - http://daneden.me/animate
|
||||
Licensed under the ☺ license (http://licence.visualidiot.com/)
|
||||
|
||||
Copyright (c) 2012 Dan Eden*/
|
||||
|
||||
.animated {
|
||||
-webkit-animation-duration: 1s;
|
||||
-moz-animation-duration: 1s;
|
||||
-o-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
-moz-animation-fill-mode: both;
|
||||
-o-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
@-webkit-keyframes shake {
|
||||
0%, 100% {-webkit-transform: translateX(0);}
|
||||
10%, 30%, 50%, 70%, 90% {-webkit-transform: translateX(-10px);}
|
||||
20%, 40%, 60%, 80% {-webkit-transform: translateX(10px);}
|
||||
}
|
||||
|
||||
@-moz-keyframes shake {
|
||||
0%, 100% {-moz-transform: translateX(0);}
|
||||
10%, 30%, 50%, 70%, 90% {-moz-transform: translateX(-10px);}
|
||||
20%, 40%, 60%, 80% {-moz-transform: translateX(10px);}
|
||||
}
|
||||
|
||||
@-o-keyframes shake {
|
||||
0%, 100% {-o-transform: translateX(0);}
|
||||
10%, 30%, 50%, 70%, 90% {-o-transform: translateX(-10px);}
|
||||
20%, 40%, 60%, 80% {-o-transform: translateX(10px);}
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% {transform: translateX(0);}
|
||||
10%, 30%, 50%, 70%, 90% {transform: translateX(-10px);}
|
||||
20%, 40%, 60%, 80% {transform: translateX(10px);}
|
||||
}
|
||||
|
||||
.shake {
|
||||
-webkit-animation-name: shake;
|
||||
-moz-animation-name: shake;
|
||||
-o-animation-name: shake;
|
||||
animation-name: shake;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,113 @@
|
|||
body {padding-top: 0px; padding-bottom: 40px; background-color: #f5f5f5}
|
||||
|
||||
.error {color:#FF0000; font-size: 13px !important}
|
||||
.stock-alert {color:#FF0000 !important}
|
||||
|
||||
#footer { text-align: center}
|
||||
.footer-menu li { display: inline; list-style-type: none; padding-right: 20px;}
|
||||
|
||||
/* Login template */
|
||||
.login-box {padding-top: 40px}
|
||||
.login-form {max-width: 400px; padding: 19px 29px 29px; margin: 0 auto 20px; background-color: #fff; border: 1px solid #e5e5e5;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.05);
|
||||
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.05);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.05);
|
||||
}
|
||||
.login-form .login-form-heading,
|
||||
.login-form .checkbox { margin-bottom: 10px}
|
||||
.login-form input[type="text"],
|
||||
.login-form label.error, label.error { color: red}
|
||||
.login-form legend { font-size:16px; font-weight: bold !important}
|
||||
|
||||
/* Subnav Toolbar */
|
||||
.subnav {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
background-color: #eeeeee;
|
||||
/* Old browsers */
|
||||
background-repeat: repeat-x;
|
||||
/* Repeat the gradient */
|
||||
background-image: -moz-linear-gradient(top, #f5f5f5 0%, #eeeeee 100%);
|
||||
/* FF3.6+ */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f5f5f5), color-stop(100%,#eeeeee));
|
||||
/* Chrome,Safari4+ */
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%,#eeeeee 100%);
|
||||
/* Chrome 10+,Safari 5.1+ */
|
||||
background-image: -ms-linear-gradient(top, #f5f5f5 0%,#eeeeee 100%);
|
||||
/* IE10+ */
|
||||
background-image: -o-linear-gradient(top, #f5f5f5 0%,#eeeeee 100%);
|
||||
/* Opera 11.10+ */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f5f5f5', endColorstr='#eeeeee',GradientType=0 );
|
||||
/* IE6-9 */
|
||||
background-image: linear-gradient(top, #f5f5f5 0%,#eeeeee 100%);
|
||||
/* W3C */
|
||||
border: 1px solid #e5e5e5;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.subnav .nav {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.subnav .nav > li > a {
|
||||
color: #333333;
|
||||
margin: 0;
|
||||
padding-top: 11px;
|
||||
padding-bottom: 11px;
|
||||
border-left: 1px solid #f5f5f5;
|
||||
border-right: 1px solid #e5e5e5;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.subnav .nav > .active > a,
|
||||
.subnav .nav > .active > a:hover {
|
||||
padding-left: 13px;
|
||||
color: #777;
|
||||
background-color: #e9e9e9;
|
||||
border-right-color: #ddd;
|
||||
border-left: 0;
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,.05);
|
||||
-moz-box-shadow: inset 0 3px 5px rgba(0,0,0,.05);
|
||||
box-shadow: inset 0 3px 5px rgba(0,0,0,.05);
|
||||
}
|
||||
|
||||
.subnav .nav > .active > a .caret,
|
||||
.subnav .nav > .active > a:hover .caret {
|
||||
border-top-color: #777;
|
||||
}
|
||||
|
||||
.subnav .nav > li:first-child > a,
|
||||
.subnav .nav > li:first-child > a:hover {
|
||||
border-left: 0;
|
||||
padding-left: 12px;
|
||||
-webkit-border-radius: 4px 0 0 4px;
|
||||
-moz-border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.subnav .nav > li:last-child > a {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.subnav .dropdown-menu {
|
||||
-webkit-border-radius: 0 0 4px 4px;
|
||||
-moz-border-radius: 0 0 4px 4px;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
/* End Subnav */
|
||||
|
||||
/* Index */
|
||||
.index-box { padding-top: 10px}
|
||||
|
||||
/* End Index */
|
||||
|
||||
/* Picking */
|
||||
.basket { min-height:60px !important}
|
||||
#send-process { text-align: right}
|
||||
/* End picking */
|
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,374 @@
|
|||
/* ===========================================================
|
||||
* bootstrap-modal.js v2.1
|
||||
* ===========================================================
|
||||
* Copyright 2012 Jordan Schroter
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================== */
|
||||
|
||||
|
||||
!function ($) {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
/* MODAL CLASS DEFINITION
|
||||
* ====================== */
|
||||
|
||||
var Modal = function (element, options) {
|
||||
this.init(element, options);
|
||||
};
|
||||
|
||||
Modal.prototype = {
|
||||
|
||||
constructor: Modal,
|
||||
|
||||
init: function (element, options) {
|
||||
this.options = options;
|
||||
|
||||
this.$element = $(element)
|
||||
.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this));
|
||||
|
||||
this.options.remote && this.$element.find('.modal-body').load(this.options.remote);
|
||||
|
||||
var manager = typeof this.options.manager === 'function' ?
|
||||
this.options.manager.call(this) : this.options.manager;
|
||||
|
||||
manager = manager.appendModal ?
|
||||
manager : $(manager).modalmanager().data('modalmanager');
|
||||
|
||||
manager.appendModal(this);
|
||||
},
|
||||
|
||||
toggle: function () {
|
||||
return this[!this.isShown ? 'show' : 'hide']();
|
||||
},
|
||||
|
||||
show: function () {
|
||||
var e = $.Event('show');
|
||||
|
||||
if (this.isShown) return;
|
||||
|
||||
this.$element.trigger(e);
|
||||
|
||||
if (e.isDefaultPrevented()) return;
|
||||
|
||||
this.escape();
|
||||
|
||||
this.tab();
|
||||
|
||||
this.options.loading && this.loading();
|
||||
},
|
||||
|
||||
hide: function (e) {
|
||||
e && e.preventDefault();
|
||||
|
||||
e = $.Event('hide');
|
||||
|
||||
this.$element.trigger(e);
|
||||
|
||||
if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false);
|
||||
|
||||
this.isShown = false;
|
||||
|
||||
this.escape();
|
||||
|
||||
this.tab();
|
||||
|
||||
this.isLoading && this.loading();
|
||||
|
||||
$(document).off('focusin.modal');
|
||||
|
||||
this.$element
|
||||
.removeClass('in')
|
||||
.removeClass('animated')
|
||||
.removeClass(this.options.attentionAnimation)
|
||||
.removeClass('modal-overflow')
|
||||
.attr('aria-hidden', true);
|
||||
|
||||
$.support.transition && this.$element.hasClass('fade') ?
|
||||
this.hideWithTransition() :
|
||||
this.hideModal();
|
||||
},
|
||||
|
||||
layout: function () {
|
||||
var prop = this.options.height ? 'height' : 'max-height',
|
||||
value = this.options.height || this.options.maxHeight;
|
||||
|
||||
if (this.options.width){
|
||||
this.$element.css('width', this.options.width);
|
||||
|
||||
var that = this;
|
||||
this.$element.css('margin-left', function () {
|
||||
if (/%/ig.test(that.options.width)){
|
||||
return -(parseInt(that.options.width) / 2) + '%';
|
||||
} else {
|
||||
return -($(this).width() / 2) + 'px';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$element.css('width', '');
|
||||
this.$element.css('margin-left', '');
|
||||
}
|
||||
|
||||
this.$element.find('.modal-body')
|
||||
.css('overflow', '')
|
||||
.css(prop, '');
|
||||
|
||||
var modalOverflow = $(window).height() - 10 < this.$element.height();
|
||||
|
||||
if (value){
|
||||
this.$element.find('.modal-body')
|
||||
.css('overflow', 'auto')
|
||||
.css(prop, value);
|
||||
}
|
||||
|
||||
if (modalOverflow || this.options.modalOverflow) {
|
||||
this.$element
|
||||
.css('margin-top', 0)
|
||||
.addClass('modal-overflow');
|
||||
} else {
|
||||
this.$element
|
||||
.css('margin-top', 0 - this.$element.height() / 2)
|
||||
.removeClass('modal-overflow');
|
||||
}
|
||||
},
|
||||
|
||||
tab: function () {
|
||||
var that = this;
|
||||
|
||||
if (this.isShown && this.options.consumeTab) {
|
||||
this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) {
|
||||
if (e.keyCode && e.keyCode == 9){
|
||||
var $next = $(this),
|
||||
$rollover = $(this);
|
||||
|
||||
that.$element.find('[data-tabindex]:enabled:not([readonly])').each(function (e) {
|
||||
if (!e.shiftKey){
|
||||
$next = $next.data('tabindex') < $(this).data('tabindex') ?
|
||||
$next = $(this) :
|
||||
$rollover = $(this);
|
||||
} else {
|
||||
$next = $next.data('tabindex') > $(this).data('tabindex') ?
|
||||
$next = $(this) :
|
||||
$rollover = $(this);
|
||||
}
|
||||
});
|
||||
|
||||
$next[0] !== $(this)[0] ?
|
||||
$next.focus() : $rollover.focus();
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
} else if (!this.isShown) {
|
||||
this.$element.off('keydown.tabindex.modal');
|
||||
}
|
||||
},
|
||||
|
||||
escape: function () {
|
||||
var that = this;
|
||||
if (this.isShown && this.options.keyboard) {
|
||||
if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1);
|
||||
|
||||
this.$element.on('keyup.dismiss.modal', function (e) {
|
||||
e.which == 27 && that.hide();
|
||||
});
|
||||
} else if (!this.isShown) {
|
||||
this.$element.off('keyup.dismiss.modal')
|
||||
}
|
||||
},
|
||||
|
||||
hideWithTransition: function () {
|
||||
var that = this
|
||||
, timeout = setTimeout(function () {
|
||||
that.$element.off($.support.transition.end);
|
||||
that.hideModal();
|
||||
}, 500);
|
||||
|
||||
this.$element.one($.support.transition.end, function () {
|
||||
clearTimeout(timeout);
|
||||
that.hideModal();
|
||||
});
|
||||
},
|
||||
|
||||
hideModal: function () {
|
||||
this.$element
|
||||
.hide()
|
||||
.trigger('hidden');
|
||||
|
||||
var prop = this.options.height ? 'height' : 'max-height';
|
||||
var value = this.options.height || this.options.maxHeight;
|
||||
|
||||
if (value){
|
||||
this.$element.find('.modal-body')
|
||||
.css('overflow', '')
|
||||
.css(prop, '');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
removeLoading: function () {
|
||||
this.$loading.remove();
|
||||
this.$loading = null;
|
||||
this.isLoading = false;
|
||||
},
|
||||
|
||||
loading: function (callback) {
|
||||
callback = callback || function () {};
|
||||
|
||||
var animate = this.$element.hasClass('fade') ? 'fade' : '';
|
||||
|
||||
if (!this.isLoading) {
|
||||
var doAnimate = $.support.transition && animate;
|
||||
|
||||
this.$loading = $('<div class="loading-mask ' + animate + '">')
|
||||
.append(this.options.spinner)
|
||||
.appendTo(this.$element);
|
||||
|
||||
if (doAnimate) this.$loading[0].offsetWidth; // force reflow
|
||||
|
||||
this.$loading.addClass('in');
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
doAnimate ?
|
||||
this.$loading.one($.support.transition.end, callback) :
|
||||
callback();
|
||||
|
||||
} else if (this.isLoading && this.$loading) {
|
||||
this.$loading.removeClass('in');
|
||||
|
||||
var that = this;
|
||||
$.support.transition && this.$element.hasClass('fade')?
|
||||
this.$loading.one($.support.transition.end, function () { that.removeLoading() }) :
|
||||
that.removeLoading();
|
||||
|
||||
} else if (callback) {
|
||||
callback(this.isLoading);
|
||||
}
|
||||
},
|
||||
|
||||
focus: function () {
|
||||
var $focusElem = this.$element.find(this.options.focusOn);
|
||||
|
||||
$focusElem = $focusElem.length ? $focusElem : this.$element;
|
||||
|
||||
$focusElem.focus();
|
||||
},
|
||||
|
||||
attention: function (){
|
||||
// NOTE: transitionEnd with keyframes causes odd behaviour
|
||||
|
||||
if (this.options.attentionAnimation){
|
||||
this.$element
|
||||
.removeClass('animated')
|
||||
.removeClass(this.options.attentionAnimation);
|
||||
|
||||
var that = this;
|
||||
|
||||
setTimeout(function () {
|
||||
that.$element
|
||||
.addClass('animated')
|
||||
.addClass(that.options.attentionAnimation);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
|
||||
this.focus();
|
||||
},
|
||||
|
||||
|
||||
destroy: function () {
|
||||
var e = $.Event('destroy');
|
||||
this.$element.trigger(e);
|
||||
if (e.isDefaultPrevented()) return;
|
||||
|
||||
this.teardown();
|
||||
},
|
||||
|
||||
teardown: function () {
|
||||
if (!this.$parent.length){
|
||||
this.$element.remove();
|
||||
this.$element = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$parent !== this.$element.parent()){
|
||||
this.$element.appendTo(this.$parent);
|
||||
}
|
||||
|
||||
this.$element.off('.modal');
|
||||
this.$element.removeData('modal');
|
||||
this.$element
|
||||
.removeClass('in')
|
||||
.attr('aria-hidden', true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* MODAL PLUGIN DEFINITION
|
||||
* ======================= */
|
||||
|
||||
$.fn.modal = function (option, args) {
|
||||
return this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('modal'),
|
||||
options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option);
|
||||
|
||||
if (!data) $this.data('modal', (data = new Modal(this, options)));
|
||||
if (typeof option == 'string') data[option].apply(data, [].concat(args));
|
||||
else if (options.show) data.show()
|
||||
})
|
||||
};
|
||||
|
||||
$.fn.modal.defaults = {
|
||||
keyboard: true,
|
||||
backdrop: true,
|
||||
loading: false,
|
||||
show: true,
|
||||
width: null,
|
||||
height: null,
|
||||
maxHeight: null,
|
||||
modalOverflow: false,
|
||||
consumeTab: true,
|
||||
focusOn: null,
|
||||
replace: false,
|
||||
resize: false,
|
||||
attentionAnimation: 'shake',
|
||||
manager: 'body',
|
||||
spinner: '<div class="loading-spinner" style="width: 200px; margin-left: -100px;"><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div></div>'
|
||||
};
|
||||
|
||||
$.fn.modal.Constructor = Modal;
|
||||
|
||||
|
||||
/* MODAL DATA-API
|
||||
* ============== */
|
||||
|
||||
$(function () {
|
||||
$(document).off('click.modal').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
|
||||
var $this = $(this),
|
||||
href = $this.attr('href'),
|
||||
$target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7
|
||||
option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());
|
||||
|
||||
e.preventDefault();
|
||||
$target
|
||||
.modal(option)
|
||||
.one('hide', function () {
|
||||
$this.focus();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
}(window.jQuery);
|
|
@ -0,0 +1,412 @@
|
|||
/* ===========================================================
|
||||
* bootstrap-modalmanager.js v2.1
|
||||
* ===========================================================
|
||||
* Copyright 2012 Jordan Schroter.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================== */
|
||||
|
||||
!function ($) {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
/* MODAL MANAGER CLASS DEFINITION
|
||||
* ====================== */
|
||||
|
||||
var ModalManager = function (element, options) {
|
||||
this.init(element, options);
|
||||
};
|
||||
|
||||
ModalManager.prototype = {
|
||||
|
||||
constructor: ModalManager,
|
||||
|
||||
init: function (element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, $.fn.modalmanager.defaults, this.$element.data(), typeof options == 'object' && options);
|
||||
this.stack = [];
|
||||
this.backdropCount = 0;
|
||||
|
||||
if (this.options.resize) {
|
||||
var resizeTimeout,
|
||||
that = this;
|
||||
|
||||
$(window).on('resize.modal', function(){
|
||||
resizeTimeout && clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(function(){
|
||||
for (var i = 0; i < that.stack.length; i++){
|
||||
that.stack[i].isShown && that.stack[i].layout();
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
createModal: function (element, options) {
|
||||
$(element).modal($.extend({ manager: this }, options));
|
||||
},
|
||||
|
||||
appendModal: function (modal) {
|
||||
this.stack.push(modal);
|
||||
|
||||
var that = this;
|
||||
|
||||
modal.$element.on('show.modalmanager', targetIsSelf(function (e) {
|
||||
|
||||
var showModal = function(){
|
||||
modal.isShown = true;
|
||||
|
||||
var transition = $.support.transition && modal.$element.hasClass('fade');
|
||||
|
||||
that.$element
|
||||
.toggleClass('modal-open', that.hasOpenModal())
|
||||
.toggleClass('page-overflow', $(window).height() < that.$element.height());
|
||||
|
||||
modal.$parent = modal.$element.parent();
|
||||
|
||||
modal.$container = that.createContainer(modal);
|
||||
|
||||
modal.$element.appendTo(modal.$container);
|
||||
|
||||
that.backdrop(modal, function () {
|
||||
|
||||
modal.$element.show();
|
||||
|
||||
if (transition) {
|
||||
//modal.$element[0].style.display = 'run-in';
|
||||
modal.$element[0].offsetWidth;
|
||||
//modal.$element.one($.support.transition.end, function () { modal.$element[0].style.display = 'block' });
|
||||
}
|
||||
|
||||
modal.layout();
|
||||
|
||||
modal.$element
|
||||
.addClass('in')
|
||||
.attr('aria-hidden', false);
|
||||
|
||||
var complete = function () {
|
||||
that.setFocus();
|
||||
modal.$element.trigger('shown');
|
||||
};
|
||||
|
||||
transition ?
|
||||
modal.$element.one($.support.transition.end, complete) :
|
||||
complete();
|
||||
});
|
||||
};
|
||||
|
||||
modal.options.replace ?
|
||||
that.replace(showModal) :
|
||||
showModal();
|
||||
}));
|
||||
|
||||
modal.$element.on('hidden.modalmanager', targetIsSelf(function (e) {
|
||||
|
||||
that.backdrop(modal);
|
||||
|
||||
if (modal.$backdrop){
|
||||
$.support.transition && modal.$element.hasClass('fade') ?
|
||||
modal.$backdrop.one($.support.transition.end, function () { that.destroyModal(modal) }) :
|
||||
that.destroyModal(modal);
|
||||
} else {
|
||||
that.destroyModal(modal);
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
modal.$element.on('destroy.modalmanager', targetIsSelf(function (e) {
|
||||
that.removeModal(modal);
|
||||
}));
|
||||
|
||||
},
|
||||
|
||||
destroyModal: function (modal) {
|
||||
|
||||
modal.destroy();
|
||||
|
||||
var hasOpenModal = this.hasOpenModal();
|
||||
|
||||
this.$element.toggleClass('modal-open', hasOpenModal);
|
||||
|
||||
if (!hasOpenModal){
|
||||
this.$element.removeClass('page-overflow');
|
||||
}
|
||||
|
||||
this.removeContainer(modal);
|
||||
|
||||
this.setFocus();
|
||||
},
|
||||
|
||||
hasOpenModal: function () {
|
||||
for (var i = 0; i < this.stack.length; i++){
|
||||
if (this.stack[i].isShown) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
setFocus: function () {
|
||||
var topModal;
|
||||
|
||||
for (var i = 0; i < this.stack.length; i++){
|
||||
if (this.stack[i].isShown) topModal = this.stack[i];
|
||||
}
|
||||
|
||||
if (!topModal) return;
|
||||
|
||||
topModal.focus();
|
||||
|
||||
},
|
||||
|
||||
removeModal: function (modal) {
|
||||
modal.$element.off('.modalmanager');
|
||||
if (modal.$backdrop) this.removeBackdrop.call(modal);
|
||||
this.stack.splice(this.getIndexOfModal(modal), 1);
|
||||
},
|
||||
|
||||
getModalAt: function (index) {
|
||||
return this.stack[index];
|
||||
},
|
||||
|
||||
getIndexOfModal: function (modal) {
|
||||
for (var i = 0; i < this.stack.length; i++){
|
||||
if (modal === this.stack[i]) return i;
|
||||
}
|
||||
},
|
||||
|
||||
replace: function (callback) {
|
||||
var topModal;
|
||||
|
||||
for (var i = 0; i < this.stack.length; i++){
|
||||
if (this.stack[i].isShown) topModal = this.stack[i];
|
||||
}
|
||||
|
||||
if (topModal) {
|
||||
this.$backdropHandle = topModal.$backdrop;
|
||||
topModal.$backdrop = null;
|
||||
|
||||
callback && topModal.$element.one('hidden',
|
||||
targetIsSelf( $.proxy(callback, this) ));
|
||||
|
||||
topModal.hide();
|
||||
} else if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
|
||||
removeBackdrop: function (modal) {
|
||||
modal.$backdrop.remove();
|
||||
modal.$backdrop = null;
|
||||
},
|
||||
|
||||
createBackdrop: function (animate) {
|
||||
var $backdrop;
|
||||
|
||||
if (!this.$backdropHandle) {
|
||||
$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
|
||||
.appendTo(this.$element);
|
||||
} else {
|
||||
$backdrop = this.$backdropHandle;
|
||||
$backdrop.off('.modalmanager');
|
||||
this.$backdropHandle = null;
|
||||
this.isLoading && this.removeSpinner();
|
||||
}
|
||||
|
||||
return $backdrop
|
||||
},
|
||||
|
||||
removeContainer: function (modal) {
|
||||
modal.$container.remove();
|
||||
modal.$container = null;
|
||||
},
|
||||
|
||||
createContainer: function (modal) {
|
||||
var $container;
|
||||
|
||||
$container = $('<div class="modal-scrollable">')
|
||||
.css('z-index', getzIndex( 'modal',
|
||||
modal ? this.getIndexOfModal(modal) : this.stack.length ))
|
||||
.appendTo(this.$element);
|
||||
|
||||
if (modal && modal.options.backdrop != 'static') {
|
||||
$container.on('click.modal', targetIsSelf(function (e) {
|
||||
modal.hide();
|
||||
}));
|
||||
} else if (modal) {
|
||||
$container.on('click.modal', targetIsSelf(function (e) {
|
||||
modal.attention();
|
||||
}));
|
||||
}
|
||||
|
||||
return $container;
|
||||
|
||||
},
|
||||
|
||||
backdrop: function (modal, callback) {
|
||||
var animate = modal.$element.hasClass('fade') ? 'fade' : '',
|
||||
showBackdrop = modal.options.backdrop &&
|
||||
this.backdropCount < this.options.backdropLimit;
|
||||
|
||||
if (modal.isShown && showBackdrop) {
|
||||
var doAnimate = $.support.transition && animate && !this.$backdropHandle;
|
||||
|
||||
modal.$backdrop = this.createBackdrop(animate);
|
||||
|
||||
modal.$backdrop.css('z-index', getzIndex( 'backdrop', this.getIndexOfModal(modal) ));
|
||||
|
||||
if (doAnimate) modal.$backdrop[0].offsetWidth; // force reflow
|
||||
|
||||
modal.$backdrop.addClass('in');
|
||||
|
||||
this.backdropCount += 1;
|
||||
|
||||
doAnimate ?
|
||||
modal.$backdrop.one($.support.transition.end, callback) :
|
||||
callback();
|
||||
|
||||
} else if (!modal.isShown && modal.$backdrop) {
|
||||
modal.$backdrop.removeClass('in');
|
||||
|
||||
this.backdropCount -= 1;
|
||||
|
||||
var that = this;
|
||||
|
||||
$.support.transition && modal.$element.hasClass('fade')?
|
||||
modal.$backdrop.one($.support.transition.end, function () { that.removeBackdrop(modal) }) :
|
||||
that.removeBackdrop(modal);
|
||||
|
||||
} else if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
|
||||
removeSpinner: function(){
|
||||
this.$spinner && this.$spinner.remove();
|
||||
this.$spinner = null;
|
||||
this.isLoading = false;
|
||||
},
|
||||
|
||||
removeLoading: function () {
|
||||
this.$backdropHandle && this.$backdropHandle.remove();
|
||||
this.$backdropHandle = null;
|
||||
this.removeSpinner();
|
||||
},
|
||||
|
||||
loading: function (callback) {
|
||||
callback = callback || function () { };
|
||||
|
||||
this.$element
|
||||
.toggleClass('modal-open', !this.isLoading || this.hasOpenModal())
|
||||
.toggleClass('page-overflow', $(window).height() < this.$element.height());
|
||||
|
||||
if (!this.isLoading) {
|
||||
|
||||
this.$backdropHandle = this.createBackdrop('fade');
|
||||
|
||||
this.$backdropHandle[0].offsetWidth; // force reflow
|
||||
|
||||
this.$backdropHandle
|
||||
.css('z-index', getzIndex('backdrop', this.stack.length))
|
||||
.addClass('in');
|
||||
|
||||
var $spinner = $(this.options.spinner)
|
||||
.css('z-index', getzIndex('modal', this.stack.length))
|
||||
.appendTo(this.$element)
|
||||
.addClass('in');
|
||||
|
||||
this.$spinner = $(this.createContainer())
|
||||
.append($spinner)
|
||||
.on('click.modalmanager', $.proxy(this.loading, this));
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
$.support.transition ?
|
||||
this.$backdropHandle.one($.support.transition.end, callback) :
|
||||
callback();
|
||||
|
||||
} else if (this.isLoading && this.$backdropHandle) {
|
||||
this.$backdropHandle.removeClass('in');
|
||||
|
||||
var that = this;
|
||||
$.support.transition ?
|
||||
this.$backdropHandle.one($.support.transition.end, function () { that.removeLoading() }) :
|
||||
that.removeLoading();
|
||||
|
||||
} else if (callback) {
|
||||
callback(this.isLoading);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* PRIVATE METHODS
|
||||
* ======================= */
|
||||
|
||||
// computes and caches the zindexes
|
||||
var getzIndex = (function () {
|
||||
var zIndexFactor,
|
||||
baseIndex = {};
|
||||
|
||||
return function (type, pos) {
|
||||
|
||||
if (typeof zIndexFactor === 'undefined'){
|
||||
var $baseModal = $('<div class="modal hide" />').appendTo('body'),
|
||||
$baseBackdrop = $('<div class="modal-backdrop hide" />').appendTo('body');
|
||||
|
||||
baseIndex['modal'] = +$baseModal.css('z-index');
|
||||
baseIndex['backdrop'] = +$baseBackdrop.css('z-index');
|
||||
zIndexFactor = baseIndex['modal'] - baseIndex['backdrop'];
|
||||
|
||||
$baseModal.remove();
|
||||
$baseBackdrop.remove();
|
||||
$baseBackdrop = $baseModal = null;
|
||||
}
|
||||
|
||||
return baseIndex[type] + (zIndexFactor * pos);
|
||||
|
||||
}
|
||||
}());
|
||||
|
||||
// make sure the event target is the modal itself in order to prevent
|
||||
// other components such as tabsfrom triggering the modal manager.
|
||||
// if Boostsrap namespaced events, this would not be needed.
|
||||
function targetIsSelf(callback){
|
||||
return function (e) {
|
||||
if (this === e.target){
|
||||
return callback.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* MODAL MANAGER PLUGIN DEFINITION
|
||||
* ======================= */
|
||||
|
||||
$.fn.modalmanager = function (option, args) {
|
||||
return this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('modalmanager');
|
||||
|
||||
if (!data) $this.data('modalmanager', (data = new ModalManager(this, option)));
|
||||
if (typeof option === 'string') data[option].apply(data, [].concat(args))
|
||||
})
|
||||
};
|
||||
|
||||
$.fn.modalmanager.defaults = {
|
||||
backdropLimit: 999,
|
||||
resize: true,
|
||||
spinner: '<div class="loading-spinner fade" style="width: 200px; margin-left: -100px;"><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div></div>'
|
||||
};
|
||||
|
||||
$.fn.modalmanager.Constructor = ModalManager
|
||||
|
||||
}(jQuery);
|
|
@ -0,0 +1,361 @@
|
|||
/* ===========================================================
|
||||
* bootstrap-tooltip.js v2.3.1
|
||||
* http://twitter.github.com/bootstrap/javascript.html#tooltips
|
||||
* Inspired by the original jQuery.tipsy by Jason Frame
|
||||
* ===========================================================
|
||||
* Copyright 2012 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================== */
|
||||
|
||||
|
||||
!function ($) {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
|
||||
/* TOOLTIP PUBLIC CLASS DEFINITION
|
||||
* =============================== */
|
||||
|
||||
var Tooltip = function (element, options) {
|
||||
this.init('tooltip', element, options)
|
||||
}
|
||||
|
||||
Tooltip.prototype = {
|
||||
|
||||
constructor: Tooltip
|
||||
|
||||
, init: function (type, element, options) {
|
||||
var eventIn
|
||||
, eventOut
|
||||
, triggers
|
||||
, trigger
|
||||
, i
|
||||
|
||||
this.type = type
|
||||
this.$element = $(element)
|
||||
this.options = this.getOptions(options)
|
||||
this.enabled = true
|
||||
|
||||
triggers = this.options.trigger.split(' ')
|
||||
|
||||
for (i = triggers.length; i--;) {
|
||||
trigger = triggers[i]
|
||||
if (trigger == 'click') {
|
||||
this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
|
||||
} else if (trigger != 'manual') {
|
||||
eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
|
||||
eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
|
||||
this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
|
||||
this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
|
||||
}
|
||||
}
|
||||
|
||||
this.options.selector ?
|
||||
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
|
||||
this.fixTitle()
|
||||
}
|
||||
|
||||
, getOptions: function (options) {
|
||||
options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
|
||||
|
||||
if (options.delay && typeof options.delay == 'number') {
|
||||
options.delay = {
|
||||
show: options.delay
|
||||
, hide: options.delay
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
, enter: function (e) {
|
||||
var defaults = $.fn[this.type].defaults
|
||||
, options = {}
|
||||
, self
|
||||
|
||||
this._options && $.each(this._options, function (key, value) {
|
||||
if (defaults[key] != value) options[key] = value
|
||||
}, this)
|
||||
|
||||
self = $(e.currentTarget)[this.type](options).data(this.type)
|
||||
|
||||
if (!self.options.delay || !self.options.delay.show) return self.show()
|
||||
|
||||
clearTimeout(this.timeout)
|
||||
self.hoverState = 'in'
|
||||
this.timeout = setTimeout(function() {
|
||||
if (self.hoverState == 'in') self.show()
|
||||
}, self.options.delay.show)
|
||||
}
|
||||
|
||||
, leave: function (e) {
|
||||
var self = $(e.currentTarget)[this.type](this._options).data(this.type)
|
||||
|
||||
if (this.timeout) clearTimeout(this.timeout)
|
||||
if (!self.options.delay || !self.options.delay.hide) return self.hide()
|
||||
|
||||
self.hoverState = 'out'
|
||||
this.timeout = setTimeout(function() {
|
||||
if (self.hoverState == 'out') self.hide()
|
||||
}, self.options.delay.hide)
|
||||
}
|
||||
|
||||
, show: function () {
|
||||
var $tip
|
||||
, pos
|
||||
, actualWidth
|
||||
, actualHeight
|
||||
, placement
|
||||
, tp
|
||||
, e = $.Event('show')
|
||||
|
||||
if (this.hasContent() && this.enabled) {
|
||||
this.$element.trigger(e)
|
||||
if (e.isDefaultPrevented()) return
|
||||
$tip = this.tip()
|
||||
this.setContent()
|
||||
|
||||
if (this.options.animation) {
|
||||
$tip.addClass('fade')
|
||||
}
|
||||
|
||||
placement = typeof this.options.placement == 'function' ?
|
||||
this.options.placement.call(this, $tip[0], this.$element[0]) :
|
||||
this.options.placement
|
||||
|
||||
$tip
|
||||
.detach()
|
||||
.css({ top: 0, left: 0, display: 'block' })
|
||||
|
||||
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
|
||||
|
||||
pos = this.getPosition()
|
||||
|
||||
actualWidth = $tip[0].offsetWidth
|
||||
actualHeight = $tip[0].offsetHeight
|
||||
|
||||
switch (placement) {
|
||||
case 'bottom':
|
||||
tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||
break
|
||||
case 'top':
|
||||
tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||
break
|
||||
case 'left':
|
||||
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
|
||||
break
|
||||
case 'right':
|
||||
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
|
||||
break
|
||||
}
|
||||
|
||||
this.applyPlacement(tp, placement)
|
||||
this.$element.trigger('shown')
|
||||
}
|
||||
}
|
||||
|
||||
, applyPlacement: function(offset, placement){
|
||||
var $tip = this.tip()
|
||||
, width = $tip[0].offsetWidth
|
||||
, height = $tip[0].offsetHeight
|
||||
, actualWidth
|
||||
, actualHeight
|
||||
, delta
|
||||
, replace
|
||||
|
||||
$tip
|
||||
.offset(offset)
|
||||
.addClass(placement)
|
||||
.addClass('in')
|
||||
|
||||
actualWidth = $tip[0].offsetWidth
|
||||
actualHeight = $tip[0].offsetHeight
|
||||
|
||||
if (placement == 'top' && actualHeight != height) {
|
||||
offset.top = offset.top + height - actualHeight
|
||||
replace = true
|
||||
}
|
||||
|
||||
if (placement == 'bottom' || placement == 'top') {
|
||||
delta = 0
|
||||
|
||||
if (offset.left < 0){
|
||||
delta = offset.left * -2
|
||||
offset.left = 0
|
||||
$tip.offset(offset)
|
||||
actualWidth = $tip[0].offsetWidth
|
||||
actualHeight = $tip[0].offsetHeight
|
||||
}
|
||||
|
||||
this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
|
||||
} else {
|
||||
this.replaceArrow(actualHeight - height, actualHeight, 'top')
|
||||
}
|
||||
|
||||
if (replace) $tip.offset(offset)
|
||||
}
|
||||
|
||||
, replaceArrow: function(delta, dimension, position){
|
||||
this
|
||||
.arrow()
|
||||
.css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
|
||||
}
|
||||
|
||||
, setContent: function () {
|
||||
var $tip = this.tip()
|
||||
, title = this.getTitle()
|
||||
|
||||
$tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
|
||||
$tip.removeClass('fade in top bottom left right')
|
||||
}
|
||||
|
||||
, hide: function () {
|
||||
var that = this
|
||||
, $tip = this.tip()
|
||||
, e = $.Event('hide')
|
||||
|
||||
this.$element.trigger(e)
|
||||
if (e.isDefaultPrevented()) return
|
||||
|
||||
$tip.removeClass('in')
|
||||
|
||||
function removeWithAnimation() {
|
||||
var timeout = setTimeout(function () {
|
||||
$tip.off($.support.transition.end).detach()
|
||||
}, 500)
|
||||
|
||||
$tip.one($.support.transition.end, function () {
|
||||
clearTimeout(timeout)
|
||||
$tip.detach()
|
||||
})
|
||||
}
|
||||
|
||||
$.support.transition && this.$tip.hasClass('fade') ?
|
||||
removeWithAnimation() :
|
||||
$tip.detach()
|
||||
|
||||
this.$element.trigger('hidden')
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
, fixTitle: function () {
|
||||
var $e = this.$element
|
||||
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
|
||||
$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
|
||||
}
|
||||
}
|
||||
|
||||
, hasContent: function () {
|
||||
return this.getTitle()
|
||||
}
|
||||
|
||||
, getPosition: function () {
|
||||
var el = this.$element[0]
|
||||
return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
|
||||
width: el.offsetWidth
|
||||
, height: el.offsetHeight
|
||||
}, this.$element.offset())
|
||||
}
|
||||
|
||||
, getTitle: function () {
|
||||
var title
|
||||
, $e = this.$element
|
||||
, o = this.options
|
||||
|
||||
title = $e.attr('data-original-title')
|
||||
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
|
||||
|
||||
return title
|
||||
}
|
||||
|
||||
, tip: function () {
|
||||
return this.$tip = this.$tip || $(this.options.template)
|
||||
}
|
||||
|
||||
, arrow: function(){
|
||||
return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
|
||||
}
|
||||
|
||||
, validate: function () {
|
||||
if (!this.$element[0].parentNode) {
|
||||
this.hide()
|
||||
this.$element = null
|
||||
this.options = null
|
||||
}
|
||||
}
|
||||
|
||||
, enable: function () {
|
||||
this.enabled = true
|
||||
}
|
||||
|
||||
, disable: function () {
|
||||
this.enabled = false
|
||||
}
|
||||
|
||||
, toggleEnabled: function () {
|
||||
this.enabled = !this.enabled
|
||||
}
|
||||
|
||||
, toggle: function (e) {
|
||||
var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
|
||||
self.tip().hasClass('in') ? self.hide() : self.show()
|
||||
}
|
||||
|
||||
, destroy: function () {
|
||||
this.hide().$element.off('.' + this.type).removeData(this.type)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* TOOLTIP PLUGIN DEFINITION
|
||||
* ========================= */
|
||||
|
||||
var old = $.fn.tooltip
|
||||
|
||||
$.fn.tooltip = function ( option ) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
, data = $this.data('tooltip')
|
||||
, options = typeof option == 'object' && option
|
||||
if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
|
||||
if (typeof option == 'string') data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.tooltip.Constructor = Tooltip
|
||||
|
||||
$.fn.tooltip.defaults = {
|
||||
animation: true
|
||||
, placement: 'top'
|
||||
, selector: false
|
||||
, template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
|
||||
, trigger: 'hover focus'
|
||||
, title: ''
|
||||
, delay: 0
|
||||
, html: false
|
||||
, container: false
|
||||
}
|
||||
|
||||
|
||||
/* TOOLTIP NO CONFLICT
|
||||
* =================== */
|
||||
|
||||
$.fn.tooltip.noConflict = function () {
|
||||
$.fn.tooltip = old
|
||||
return this
|
||||
}
|
||||
|
||||
}(window.jQuery);
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,19 @@
|
|||
{% extends "default/layout.html" %}
|
||||
{% block title %}404, Page Not Found{% endblock %}
|
||||
{% block body %}
|
||||
<div class="row">
|
||||
<div class="error">
|
||||
<h1>404, Page Not Found</h1>
|
||||
<blockquote>
|
||||
<p>The requested page,</p>
|
||||
<p>cannot be found — </p>
|
||||
<p>We're sorry.</p>
|
||||
</blockquote>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}<ul class=error>
|
||||
{% for message in messages %}<li>{{ message }}</li>{% endfor %}
|
||||
</ul>{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,18 @@
|
|||
{% extends "default/layout.html" %}
|
||||
{% block title %}500, Internal Server Error{% endblock %}
|
||||
{% block body %}
|
||||
<div class="row">
|
||||
<div class="error">
|
||||
<h1>500, Internal Server Error</h1>
|
||||
<blockquote>
|
||||
<p>The server encountered an unexpected error.</p>
|
||||
<p>Please try again later.</p>
|
||||
</blockquote>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}<ul class=error>
|
||||
{% for message in messages %}<li>{{ message }}</li>{% endfor %}
|
||||
</ul>{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,31 @@
|
|||
{% extends "default/layout.html" %}
|
||||
{% block title %}{{ _("Select a cart") }}{% endblock %}
|
||||
{% block body %}
|
||||
{% include 'default/nav.html' %}
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
{% if session.order %}<p>{{ _("Order products by") }}: <strong>{{ session.order }}</strong></p>{% endif %}
|
||||
<table class="table table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ _("Name") }}</th>
|
||||
<th>{{ _("Baskets") }}</th>
|
||||
<th>{{ _("User") }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for cart in carts %}
|
||||
<tr>
|
||||
<td>{{ cart.name }}</td>
|
||||
<td>{{ cart.rows*cart.columns }}</td>
|
||||
<td>{% if cart.user_id %}{{ cart.user_id }}{% endif %}</td>
|
||||
<td>{% if not cart.user_id %}<a href="{{ url_for('cart') }}?cart={{ cart.id }}" class="label label-success">{{ _("Get this cart") }}</a>{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<div id="help-modal" class="modal hide fade" tabindex="-1"></div>
|
||||
|
||||
<script id="help-modal" type="text/javascript">
|
||||
var $modal = $('#help-modal');
|
||||
|
||||
$('.nav .help').on('click', function(){
|
||||
// create the backdrop and wait for next modal to be triggered
|
||||
$('body').modalmanager('loading');
|
||||
|
||||
setTimeout(function(){
|
||||
$modal.load('{{ url_for("help") }}', '', function(){
|
||||
$modal.modal();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
$modal.on('click', '.update', function(){
|
||||
$modal.modal('loading');
|
||||
setTimeout(function(){
|
||||
$modal
|
||||
.modal('loading')
|
||||
.find('.modal-body')
|
||||
.prepend('<div class="alert alert-info fade in">' +
|
||||
'Updated!<button type="button" class="close" data-dismiss="alert">×</button>' +
|
||||
'</div>');
|
||||
}, 1000);
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,10 @@
|
|||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h1>{{ config['TITLE'] }}</h1>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ content|safe }}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" data-dismiss="modal" class="btn">{{ _("Close") }}</button>
|
||||
</div>
|
|
@ -0,0 +1,37 @@
|
|||
{% extends "default/layout.html" %}
|
||||
{% block title %}{{ _("Dashboard") }}{% endblock %}
|
||||
{% block body %}
|
||||
{% include 'default/nav.html' %}
|
||||
<div class="container-fluid">
|
||||
<div class="subnav">
|
||||
<ul class="nav nav-pills">
|
||||
<li><a href="{{ url_for('cart') }}">{% if not session.cart %} {{ _("Select a cart") }} {% else %}{{ _("Change cart") }}{% endif %}</a></li>
|
||||
<li><a href="{{ url_for('picking') }}">{{ _("Process pickings") }}</a></li>
|
||||
<li><a href="#" class="help" data-toggle="modal">{{ _("Help") }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row index-box">
|
||||
<div class="span4">
|
||||
<div class="well">
|
||||
<h2 class="muted">1. {{ _("Select a cart") }}</h2>
|
||||
<p>{{ _("Go to your preferences a select a cart do you work. Remember when not working in warehouse, do logout") }}<br/><a class="btn btn-warning" href="{{ url_for('cart') }}">{{ _("Go") }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<div class="well">
|
||||
<h2 class="muted">2. {{ _("Process pickings") }}</h2>
|
||||
<p>{{ _("When process pickings, select products in your warehouse and put in you backet cart.") }}<br/><a class="btn btn-warning" href="{{ url_for('picking') }}">{{ _("Go") }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<div class="well">
|
||||
<h2 class="muted">3. {{ _("Make picking") }}</h2>
|
||||
<p>{{ _("When finish selection products, return your picking area and make delivery package.") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="{{ config['LANGUAGE'] }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="{% block description %}{% endblock %}">
|
||||
<meta name="author" content="{{ config['AUTHOR'] }}">
|
||||
<title>{% block title %}{% endblock %} - {{ config['TITLE'] }}</title>
|
||||
<link href="{{ url_for('static', filename='default/css/bootstrap.css') }}" rel="stylesheet" type="text/css">
|
||||
<link href="{{ url_for('static', filename='default/css/bootstrap-responsive.css') }}" rel="stylesheet" type="text/css">
|
||||
<link href="{{ url_for('static', filename='default/css/custom.css') }}" rel="stylesheet" type="text/css">
|
||||
<link href="{{ url_for('static', filename='default/css/bootstrap-modal.css') }}" rel="stylesheet" type="text/css">
|
||||
<script src="{{ url_for('static', filename='default/js/jquery-1.7.2.min.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ url_for('static', filename='default/js/bootstrap.min.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ url_for('static', filename='default/js/bootstrap-tooltip.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ url_for('static', filename='default/js/bootstrap-modalmanager.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ url_for('static', filename='default/js/bootstrap-modal.js') }}" type="text/javascript"></script>
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{% block body %}{% endblock %}
|
||||
{% include 'default/footer.html' %}
|
||||
</div>
|
||||
</body>
|
|
@ -0,0 +1,53 @@
|
|||
{% extends "default/layout.html" %}
|
||||
{% block title %}{{ _("Login") }}{% endblock %}
|
||||
{% block body %}
|
||||
<script src="{{ url_for('static', filename='default/js/jquery.validate.js') }}" type="text/javascript"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$().ready(function() {
|
||||
$("#login-form").validate({
|
||||
rules: {
|
||||
username: "required",
|
||||
password: "required",
|
||||
},
|
||||
messages: {
|
||||
username: "{{ _('Add a user name') }}",
|
||||
password: "{{ _('Add a password') }}",
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="login-box">
|
||||
<form id="login-form" class="login-form" method="POST" action="">
|
||||
<fieldset>
|
||||
<div id="legend">
|
||||
<legend class="">{{ config['TITLE'] }}</legend>
|
||||
</div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}<ul class=error>
|
||||
{% for message in messages %}<li>{{ message }}</li>{% endfor %}
|
||||
</ul>{% endif %}
|
||||
{% endwith %}
|
||||
{{ form.csrf_token }}
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="username">{{ _("Username") }}</label>
|
||||
<div class="controls">
|
||||
{{ form.username(size=20) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="password">{{ _("Password") }}</label>
|
||||
<div class="controls">
|
||||
{{ form.password(size=20) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<button class="btn btn-large btn-primary" type="submit">{{ _("Login") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,46 @@
|
|||
<div class="navbar navbar-inverse nav">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</a>
|
||||
<a class="brand" href="/">{{ config['TITLE'] }}</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="{{ url_for('picking') }}"><i class="icon-pencil icon-white"></i> {{ _("Process pickings") }}</a></li>
|
||||
</ul>
|
||||
<div class="pull-right">
|
||||
<ul class="nav pull-right">
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ _("Welcome") }}, {{ session.username }} {% if session.cart %}- {{ session.cart_name }}{% endif %}<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="nav-header">{{ _("Order by") }}</a></li>
|
||||
<li><a href="{{ url_for('cart') }}?order=location">{{ _("Location") }}</a></li>
|
||||
<li><a href="{{ url_for('cart') }}?order=manufacturer">{{ _("Manufacturer") }}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ url_for('cart') }}"><i class="icon-cog"></i> {% if not session.cart %} {{ _("Select a cart") }} {% else %}{{ _("Change cart") }}{% endif %}</a></li>
|
||||
<li><a href="#" class="help" data-toggle="modal"><i class="icon-book"></i> {{ _("Help") }}</a></li>
|
||||
<li><a href="/logout"><i class="icon-off"></i> {{ _("Logout") }}</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% with messages = get_flashed_messages() %}{% if messages %}
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="span12 well">
|
||||
<ul class=error>
|
||||
{% for message in messages %}<li>{{ message }}</li>{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}{% endwith %}
|
|
@ -0,0 +1,126 @@
|
|||
{% extends "default/layout.html" %}
|
||||
{% block title %}{{ _("Select a cart") }}{% endblock %}
|
||||
{% block head %}<script src="{{ url_for('static', filename='default/js/jquery.validate.js') }}" type="text/javascript"></script>{% endblock %}
|
||||
{% block body %}
|
||||
{% include 'default/nav.html' %}
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<table class="table table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ _("Code") }}</th>
|
||||
<th>{{ _("Product") }}</th>
|
||||
<th>{{ _("Qty") }}</th>
|
||||
<th>{{ _("Qty Available") }}</th>
|
||||
<th>{{ _("Rack") }}</th>
|
||||
<th>{{ _("Row") }}</th>
|
||||
<th>{{ _("Case") }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if not products %}<tr><td colspan="7">{{ _('There are not pickings to process') }}</td></tr>{% endif %}
|
||||
{% for product in products %}
|
||||
<tr class="{% if product.qty_available < 0 %}stock-alert{% endif %}">
|
||||
<td><strong>{{ product.code }}</strong></td>
|
||||
<td><a href="#{{ product.id }}" data-toggle="modal">{{ product.name }}</a></td>
|
||||
<td><strong>{{ product.qty }}</strong></td>
|
||||
<td>{{ product.qty_available }}</td>
|
||||
<td>{% if product.loc_rack %}{{ product.loc_rack }}{% endif %}</td>
|
||||
<td>{% if product.loc_row %}{{ product.loc_row }}{% endif %}</td>
|
||||
<td>{% if product.loc_case %}{{ product.loc_case }}{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="#" id="basket-form" class="form-horizontal" method="POST">
|
||||
{% for product in products %} <div id="{{ product.id }}" class="modal hide fade" tabindex="-1" data-width="760">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>{{ product.code }} - {{ product.name }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row-fluid">{% set count = 0 %}{% for cell in range(session.cart_rows*session.cart_columns) %}{% if count < grid|length %}
|
||||
{% if count is divisibleby session.cart_columns %}{% if not count == 0 %}</div>
|
||||
<div class="row-fluid">{% endif %}{% endif %}
|
||||
<div class="span{{ (12 / session.cart_columns)|floatwithoutdecimal }} basket">{% set cell = loop.index %}{% set picking_cell_name = grid|pickingname(cell) %}
|
||||
<h4>{{ cell }} - {{ picking_cell_name }}</h4>{% for picking in product.pickings %}{% if picking.name == picking_cell_name %}
|
||||
<p>
|
||||
<input type="number" name="{{picking.move}}" min="1" value="{% if not product.qty_available < 0 %}{{ picking.qty }}{% endif %}" class="required" required><br/>
|
||||
{{ _('Qty added in this basket ') }} {% if product.qty_available < 0 %}<span class="stock-alert">({{ _('Qty') }}: {{ picking.qty }})</span>{% endif %}
|
||||
</p>{% endif %}{% endfor %}
|
||||
</div>{% set count = count + 1 %}{% endif %}{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" data-dismiss="modal" class="btn">Close</button>
|
||||
</div>
|
||||
</div>{% endfor %}
|
||||
<div id="send-process">
|
||||
<button type="submit" class="btn btn-primary">{{ _('Process') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% if grid|length %}<!-- legend -->
|
||||
<hr/>
|
||||
<h4>{{ _('Grid Cart') }}</h4>
|
||||
<div class="row-fluid">{% set count = 0 %}{% for cell in range(session.cart_rows*session.cart_columns) %}{% if count < grid|length %}
|
||||
{% if count is divisibleby session.cart_columns %}{% if not count == 0 %}</div>
|
||||
<div class="row-fluid">{% endif %}{% endif %}
|
||||
<div class="span{{ (12 / session.cart_columns)|floatwithoutdecimal }}">{% set cell = loop.index %}{% set picking_cell_name = grid|pickingname(cell) %}
|
||||
<strong>{{ cell }} - {{ picking_cell_name }}</strong>
|
||||
</div>{% set count = count + 1 %}{% endif %}{% endfor %}
|
||||
</div>{% endif %}
|
||||
|
||||
<!-- Modal Window done -->
|
||||
<div id="send-done" class="modal hide fade" tabindex="-1" data-backdrop="static" data-keyboard="false">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>{{ _('Send quantity products successfully') }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p><a href="{{ url_for('picking') }}">{{ _('Get more products/pickings to do') }}</a></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" data-dismiss="modal" class="btn">{{ _('Done') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Window error -->
|
||||
<div id="send-error" class="modal hide fade" tabindex="-1" data-backdrop="static" data-keyboard="false">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>{{ _('Error!') }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{{ _('Qty are integer values? Review your cart and resend') }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" data-dismiss="modal" class="btn">{{ _('Check') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
{% if not products %}$("#send-process").hide();{% endif %}
|
||||
$("#basket-form").submit(function () {
|
||||
var data = $('#basket-form').serializeArray();
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/basket",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data:JSON.stringify(data),
|
||||
success: function(data) {
|
||||
$('#send-done').modal('show');
|
||||
$("#send-process").hide();
|
||||
},
|
||||
error:function(data){
|
||||
$('#send-error').modal('show');
|
||||
},
|
||||
});
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue