L'outil de gestion de stock de composants électroniques du Tetalab.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tetastock.py 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8
  3. import os
  4. import datetime
  5. import bcrypt
  6. import binascii
  7. import math
  8. import psycopg2
  9. from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
  10. from flask_sqlalchemy import SQLAlchemy
  11. from functools import wraps
  12. ########################################################################
  13. # App settings
  14. ########################################################################
  15. app = Flask(__name__)
  16. app.config.from_pyfile('config.py')
  17. app.secret_key = '446307a5f61c2bb810436b2ee0f903f2'
  18. app.debug = False
  19. app.static_url_path='/static'
  20. db = SQLAlchemy(app)
  21. ########################################################################
  22. # Database
  23. ########################################################################
  24. class Stock_users(db.Model):
  25. __tablename__ = 'stock_users'
  26. id = db.Column(db.Integer, primary_key=True)
  27. mail = db.Column(db.Text, nullable=False)
  28. password = db.Column(db.Text, nullable=False)
  29. name = db.Column(db.Text, nullable=False)
  30. class Stock_componants(db.Model):
  31. __tablename__ = 'stock_componants'
  32. id = db.Column(db.Integer, primary_key=True)
  33. reference = db.Column(db.Text, nullable=False)
  34. designation = db.Column(db.Text, nullable=False)
  35. last_price = db.Column(db.Float)
  36. mean_price = db.Column(db.Float)
  37. quantity = db.Column(db.Integer)
  38. min_quantity = db.Column(db.Integer)
  39. place = db.Column(db.Text, nullable=False)
  40. provider_id = db.Column(db.Integer, nullable=False)
  41. class Stock_providers(db.Model):
  42. __tablename__ = 'stock_providers'
  43. id = db.Column(db.Integer, primary_key=True)
  44. name = db.Column(db.Text, nullable=False)
  45. address = db.Column(db.Text)
  46. mail = db.Column(db.Text)
  47. url = db.Column(db.Text)
  48. comment = db.Column(db.Text)
  49. class Stock_kits(db.Model):
  50. __tablename__ = 'stock_kits'
  51. id = db.Column(db.Integer, primary_key=True)
  52. name = db.Column(db.Text, nullable=False)
  53. designation = db.Column(db.Text, nullable=False)
  54. class Stock_kit_compositions(db.Model):
  55. __tablename__ = 'stock_kit_compositions'
  56. id = db.Column(db.Integer, primary_key=True)
  57. kit_id = db.Column(db.Integer, db.ForeignKey('stock_kits.id'), nullable=False)
  58. componant_id = db.Column(db.Integer, db.ForeignKey('stock_componants.id'), nullable=False)
  59. quantity = db.Column(db.Integer, nullable=False)
  60. class Stock_orders(db.Model):
  61. __tablename__ = 'stock_orders'
  62. id = db.Column(db.Integer, primary_key=True)
  63. componant_id = db.Column(db.Integer, db.ForeignKey('stock_componants.id'))
  64. componant_quantity = db.Column(db.Integer, nullable=False)
  65. date = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
  66. injected = db.Column(db.Boolean, nullable=False, default=False)
  67. ########################################################################
  68. # Here comes the fun
  69. ########################################################################
  70. def get_max_kit(kit_id):
  71. """ Get max available kit from kit.id """
  72. default_max_kit = float("inf")
  73. max_kit = default_max_kit
  74. composition = Stock_kit_compositions.query.filter_by(kit_id=kit_id).with_entities(
  75. Stock_kit_compositions.componant_id,
  76. Stock_kit_compositions.quantity).all()
  77. for c_componant in composition:
  78. componant = Stock_componants.query.filter_by(id=c_componant.componant_id).first()
  79. if componant:
  80. try:
  81. mkit = int(componant.quantity) / int(c_componant.quantity)
  82. except ZeroDivisionError as e:
  83. print "[+] Error at get_max_kit:"
  84. print "------------------------------"
  85. print "%s" % e.message
  86. print "------------------------------"
  87. if mkit < max_kit:
  88. max_kit = mkit
  89. if max_kit == default_max_kit:
  90. max_kit = 0
  91. return max_kit
  92. def sync_cookies(response, session):
  93. """ Sync cookies with session """
  94. for key in session:
  95. response.set_cookie(key, value=str(session[key]))
  96. #~ if key != u'session':
  97. #~ print '[c]', key, session[key]
  98. def sync_session(request, session):
  99. """ Sync session with cookies"""
  100. for key in request.cookies:
  101. try:
  102. old = str(session[key])
  103. session[key] = int(str(request.cookies[key].encode('utf8')))
  104. except ValueError:
  105. # Value is not an int, will be treated as string
  106. session[key] = str(request.cookies[key].encode('utf8'))
  107. except KeyError:
  108. # Key does not exist in session
  109. try:
  110. session[key] = int(str(request.cookies[key].encode('utf8')))
  111. except ValueError:
  112. # Value is not an int, will be treated as string
  113. session[key] = str(request.cookies[key].encode('utf8'))
  114. #~ if key != u'session':
  115. #~ print '[s]', key, request.cookies[key]
  116. def check_user(request, session):
  117. """ Check user credentials """
  118. if session['token'] and request.cookies['token']:
  119. if len(session['token']) > 0 and len(request.cookies['token']) > 0:
  120. if session['token'] == request.cookies['token']:
  121. return True
  122. return False
  123. if 'login' not in request.cookies or 'password' not in request.cookies:
  124. return False
  125. if request.cookies['login'] and request.cookies['password']:
  126. if request.cookies['login'] > 0 and request.cookies['password'] > 0:
  127. hashed = Stock_users.query.filter_by(mail=request.cookies['login']).with_entities(Stock_users.password).first()
  128. if hashed is None:
  129. # User is unknown
  130. return False
  131. password = request.cookies['password'].encode('utf8')
  132. hashed = hashed[0].encode('utf8')
  133. if bcrypt.checkpw(password, hashed):
  134. session['password'] = ''
  135. session['login'] = ''
  136. session['token'] = binascii.hexlify(os.urandom(42))
  137. return True
  138. # Password mismatch
  139. return False
  140. def resume_session(func):
  141. """ Resume pending session """
  142. @wraps(func)
  143. def check(*args, **kwargs):
  144. # A motherfuckin' bunch of defaults values
  145. css='neutral'
  146. empty=u''
  147. limit = 12
  148. offset = 0
  149. page = 1
  150. nexthop = offset + limit
  151. prevhop = offset
  152. order = u'asc'
  153. order_refresh = 0
  154. c_sort = u'reference'
  155. c_provider = 0
  156. c_count = 0
  157. p_sort = u'name'
  158. p_count = 0
  159. k_sort = u'name'
  160. k_count = 0
  161. kc_quantity = 0
  162. kc_limit = 3
  163. if not u'css' in session:
  164. session[u'css'] = css
  165. if not u'token' in session:
  166. session[u'token'] = empty
  167. if not u'password' in session:
  168. session[u'password'] = empty
  169. if not u'login' in session:
  170. session[u'login'] = empty
  171. if not u'session' in session:
  172. session[u'session'] = empty
  173. if not u'c_limit' in session:
  174. session[u'c_limit'] = limit
  175. if not u'c_offest' in session:
  176. session[u'c_offset'] = offset
  177. if not u'c_sort' in session:
  178. session['c_sort'] = c_sort
  179. if not u'c_order' in session:
  180. session[u'c_order'] = order
  181. if not u'c_order_refresh' in session:
  182. session[u'c_order_refresh'] = order_refresh
  183. if not u'c_page' in session:
  184. session[u'c_page'] = page
  185. if not u'c_nexthop' in session:
  186. session[u'c_nexthop'] = nexthop
  187. if not u'c_prevhop' in session:
  188. session['c_prevhop'] = prevhop
  189. if not u'c_reference' in session:
  190. session[u'c_reference'] = empty
  191. if not u'c_designation' in session:
  192. session[u'c_designation'] = empty
  193. if not u'c_place' in session:
  194. session[u'c_place'] = empty
  195. if not u'c_provider' in session:
  196. session[u'c_provider'] = c_provider
  197. if not u'c_count' in session:
  198. session[u'c_count'] = c_count
  199. if not u'p_sort' in session:
  200. session[u'p_sort'] = p_sort
  201. if not u'p_order' in session:
  202. session[u'p_order'] = order
  203. if not u'p_order_refresh' in session:
  204. session[u'p_order_refresh'] = order_refresh
  205. if not u'p_page' in session:
  206. session[u'p_page'] = page
  207. if not u'p_nexthop' in session:
  208. session[u'p_nexthop'] = nexthop
  209. if not u'p_prevhop' in session:
  210. session[u'p_prevhop'] = prevhop
  211. if not u'p_offset' in session:
  212. session[u'p_offset'] = offset
  213. if not u'p_limit' in session:
  214. session[u'p_limit'] = limit
  215. if not u'p_name' in session:
  216. session[u'p_name'] = empty
  217. if not u'p_address' in session:
  218. session[u'p_address'] = empty
  219. if not u'p_mail' in session:
  220. session[u'p_mail'] = empty
  221. if not u'p_url' in session:
  222. session[u'p_url'] = empty
  223. if not u'p_comment' in session:
  224. session[u'p_comment'] = empty
  225. if not u'p_count' in session:
  226. session['p_count'] = p_count
  227. if not u'k_sort' in session:
  228. session[u'k_sort'] = k_sort
  229. if not u'k_order' in session:
  230. session[u'k_order'] = order
  231. if not u'k_order_refresh' in session:
  232. session[u'k_order_refresh'] = order_refresh
  233. if not u'k_page' in session:
  234. session[u'k_page'] = page
  235. if not u'k_nexthop' in session:
  236. session[u'k_nexthop'] = nexthop
  237. if not u'k_prevhop' in session:
  238. session[u'k_prevhop'] = prevhop
  239. if not u'k_offset' in session:
  240. session[u'k_offset'] = offset
  241. if not u'k_limit' in session:
  242. session[u'k_limit'] = limit
  243. if not u'k_name' in session:
  244. session[u'k_name'] = empty
  245. if not u'k_address' in session:
  246. session[u'k_address'] = empty
  247. if not u'k_mail' in session:
  248. session[u'k_mail'] = empty
  249. if not u'k_url' in session:
  250. session[u'k_url'] = empty
  251. if not u'k_designation' in session:
  252. session[u'k_designation'] = empty
  253. if not u'k_count' in session:
  254. session[u'k_count'] = k_count
  255. if not u'kc_limit' in session:
  256. session[u'kc_limit'] = kc_limit
  257. if not u'kc_componant_id' in session:
  258. session[u'kc_componant_id'] = empty
  259. if not u'kc_quantity' in session:
  260. session[u'kc_quantity'] = kc_quantity
  261. if not u'kc_designation' in session:
  262. session[u'kc_designation'] = empty
  263. if not u'kc_reference' in session:
  264. session[u'kc_reference'] = empty
  265. # Cookies/session sync
  266. sync_session(request, session)
  267. # Switch sort order
  268. refresh = {u'desc': u'asc', u'asc': u'desc'}
  269. if session[u'c_order_refresh'] == 1:
  270. session[u'c_order'] = refresh[session[u'c_order']]
  271. session[u'c_order_refresh'] = 0
  272. if session[u'p_order_refresh'] == 1:
  273. session[u'p_order'] = refresh[session[u'p_order']]
  274. session[u'p_order_refresh'] = 0
  275. if session[u'k_order_refresh'] == 1:
  276. session[u'k_order'] = refresh[session[u'k_order']]
  277. session[u'k_order_refresh'] = 0
  278. # Check for valid session
  279. if not check_user(request, session):
  280. # User is not logged in, send him back to login page
  281. return render_template('login.html', css=session[u'css'])
  282. # Everything's fine
  283. return func(*args, **kwargs)
  284. return check
  285. ########################################################################
  286. # Routes
  287. ########################################################################
  288. @app.errorhandler(404)
  289. @resume_session
  290. def page_not_found(e):
  291. """ 404 not found """
  292. return render_template('error.html', css=session[u'css']), 404
  293. @app.route("/", methods=['GET', 'POST'])
  294. @resume_session
  295. def authenticate():
  296. """ Friend or foo ? """
  297. response = app.make_response(render_template('index.html', css=session[u'css']))
  298. sync_cookies(response, session)
  299. return response
  300. ########################################################################
  301. # Componants
  302. ########################################################################
  303. @app.route('/componants', methods=['GET', 'POST'])
  304. @resume_session
  305. def componants():
  306. """ Componants list """
  307. providers = Stock_providers.query.order_by(Stock_providers.id).all()
  308. return render_template('componants.html',
  309. providers=providers,
  310. reference=session[u'c_reference'].decode('utf8'),
  311. designation=session[u'c_designation'].decode('utf8'),
  312. place=session[u'c_place'].decode('utf8'),
  313. provider_id=session[u'c_provider'],
  314. css=session[u'css'])
  315. @app.route('/componants/<componant_id>', methods=['GET', 'POST'])
  316. @resume_session
  317. def get_componant(componant_id):
  318. """ Edit componant """
  319. try:
  320. componant_id = int(componant_id)
  321. except ValueError as e:
  322. return render_template('error.html', css=session[u'css']), 404
  323. componant = Stock_componants.query.filter_by(id=componant_id).first()
  324. if componant:
  325. providers = Stock_providers.query.order_by(Stock_providers.name).all()
  326. provider = componant.provider_id
  327. provider = Stock_providers.query.filter_by(id=provider).first()
  328. return render_template('componant.html',
  329. componant=componant,
  330. providers=providers,
  331. provider=provider,
  332. css=session[u'css'])
  333. return render_template('error.html', css=session[u'css']), 404
  334. @app.route('/componants/update/<componant_id>', methods=['POST'])
  335. @resume_session
  336. def update_componant(componant_id):
  337. """ Update componant field"""
  338. field = request.form['field']
  339. value = request.form['value']
  340. if field and value:
  341. try:
  342. componant = Stock_componants.query.filter_by(id=componant_id).first()
  343. setattr(componant, field, value)
  344. commit = db.session.commit()
  345. if commit == None:
  346. return 'OK'
  347. except Exception as e:
  348. pass
  349. return 'KO'
  350. @app.route('/componants/delete/<componant_id>', methods=['GET', 'POST'])
  351. @resume_session
  352. def delete_componant(componant_id):
  353. """ Delete componant """
  354. try:
  355. componant_id = int(componant_id)
  356. Stock_componants.query.filter_by(id=componant_id).delete()
  357. db.session.commit()
  358. except ValueError as e:
  359. return render_template('error.html', css=session[u'css']), 404
  360. except Exception as e:
  361. db.session.rollback()
  362. print "[+] Error at delete_componant:"
  363. print "------------------------------"
  364. print "%s" % e.message
  365. print "------------------------------"
  366. return componants()
  367. @app.route('/componants/new', methods=['POST'])
  368. @resume_session
  369. def new_componant():
  370. """ Add componant """
  371. componant = Stock_componants(reference=session[u'c_reference'].decode('utf8'),
  372. designation=session[u'c_designation'].decode('utf8'),
  373. last_price=0,
  374. mean_price=0,
  375. quantity=0,
  376. min_quantity=0,
  377. place=session[u'c_place'].decode('utf8'),
  378. provider_id=session[u'c_provider'])
  379. try:
  380. db.session.add(componant)
  381. commit = db.session.commit()
  382. except Exception as e:
  383. db.session.rollback()
  384. print "[+] Error at new_componant:"
  385. print "------------------------------"
  386. print "%s" % e.message
  387. print "------------------------------"
  388. return 'KO'
  389. if commit != None:
  390. return 'KO'
  391. return 'OK'
  392. ## Componants update result set
  393. @app.route('/componants/update', methods=['GET', 'POST'])
  394. @resume_session
  395. def update_componants():
  396. """ Display componants list """
  397. # search by reference
  398. like = '%s%s%s' % ('%', str(session[u'c_reference']), '%')
  399. componants = Stock_componants.query.filter(Stock_componants.reference.like(like))
  400. # search by designation
  401. like = '%s%s%s' % ('%', str(session[u'c_designation']), '%')
  402. componants = componants.filter(Stock_componants.designation.like(like))
  403. # search by place
  404. like = '%s%s%s' % ('%', str(session[u'c_place']),'%')
  405. componants = componants.filter(Stock_componants.place.like(like))
  406. # search by provider
  407. if session['c_provider'] > 1:
  408. componants = componants.filter_by(provider_id=session[u'c_provider'])
  409. # Pages calculation
  410. session[u'c_count'] = componants.count()
  411. session[u'c_pagecount'] = int(math.ceil(session[u'c_count'] / float(session[u'c_limit'])))
  412. session[u'c_page'] = int(math.ceil(float(float(session[u'c_offset']) + 1) / float(session[u'c_limit'])))
  413. if session[u'c_page'] > session[u'c_pagecount']:
  414. session[u'c_page'] = session[u'c_pagecount']
  415. session[u'c_offset'] = 0
  416. session[u'c_nexthop'] = session[u'c_offset'] + session[u'c_limit']
  417. if session[u'c_nexthop'] > session[u'c_count'] - 1:
  418. session[u'c_nexthop'] = int(session[u'c_offset'])
  419. session[u'c_prevhop'] = int(session[u'c_offset']) - session[u'c_limit']
  420. if session[u'c_prevhop'] < 0:
  421. session[u'c_prevhop'] = 0
  422. # Sorting
  423. sort = getattr(Stock_componants, session[u'c_sort'])
  424. if session[u'c_order'] == u'desc':
  425. sort = getattr(Stock_componants, session[u'c_sort']).desc()
  426. componants = componants.order_by(sort)
  427. # Applying offset
  428. componants = componants.offset(session[u'c_offset'])
  429. # Applying limit
  430. componants = componants.limit(session[u'c_limit'])
  431. # Get result
  432. componants = componants.all()
  433. response = app.make_response(render_template('result_componants.html',
  434. componants=componants,
  435. offset=session[u'c_offset'] ,
  436. nexthop=session[u'c_nexthop'],
  437. prevhop=session[u'c_prevhop'],
  438. page_count=session[u'c_pagecount'],
  439. page=session[u'c_page'],
  440. sort=session[u'c_sort'].decode('utf8'),
  441. order=session[u'c_order'].decode('utf8'),
  442. row_count=session[u'c_count']))
  443. sync_cookies(response, session)
  444. return response
  445. ########################################################################
  446. # Orders
  447. ########################################################################
  448. def compute_mean_price(componant_id, price, quantity):
  449. """ Compute mean price """
  450. try:
  451. componant_id = int(componant_id)
  452. price = float(price)
  453. quantity = float(quantity)
  454. except ValueError:
  455. # bad parameters
  456. return -1
  457. componant = Stock_componants.query.filter_by(id=componant_id).first()
  458. if componant:
  459. actual_mean_price = componant.mean_price
  460. actual_quantity = componant.quantity
  461. actual_total = actual_mean_price * actual_quantity
  462. order_total = price * quantity
  463. grand_total = order_total + actual_total
  464. new_mean_price = grand_total / (actual_quantity + quantity)
  465. return new_mean_price
  466. # Componant does not exist
  467. return -1
  468. @app.route('/orders/in/<componant_id>')
  469. @resume_session
  470. def in_componants(componant_id):
  471. """ Incoming order """
  472. return render_template('wip.html', css=session[u'css'])
  473. @app.route('/orders/out/<componant_id>')
  474. @resume_session
  475. def out_componants(componant_id):
  476. """ Outgoing order """
  477. return render_template('wip.html', css=session[u'css'])
  478. ########################################################################
  479. # Providers
  480. ########################################################################
  481. @app.route('/providers', methods=['GET', 'POST'])
  482. @resume_session
  483. def providers():
  484. """ Providers list """
  485. return render_template('providers.html',
  486. name=session[u'p_name'].decode('utf8'),
  487. address=session[u'p_address'].decode('utf8'),
  488. mail=session[u'p_mail'].decode('utf8'),
  489. url=session[u'p_url'].decode('utf8'),
  490. comment=session[u'p_comment'].decode('utf8'),
  491. css=session[u'css'])
  492. @app.route('/providers/<provider_id>')
  493. @resume_session
  494. def get_provider(provider_id):
  495. """ Edit provider """
  496. try:
  497. provider_id = int(provider_id)
  498. except ValueError as e:
  499. return render_template('error.html', css=session[u'css']), 404
  500. provider = Stock_providers.query.filter_by(id=provider_id).first()
  501. if provider:
  502. return render_template('provider.html', provider=provider, css=session[u'css'])
  503. return render_template('error.html', css=session[u'css']), 404
  504. @app.route('/providers/update/<provider_id>', methods=['POST'])
  505. @resume_session
  506. def update_provider(provider_id):
  507. """ Update provider field"""
  508. field = request.form['field']
  509. value = request.form['value']
  510. if field and value:
  511. try:
  512. provider = Stock_providers.query.filter_by(id=provider_id).first()
  513. setattr(provider, field, value)
  514. commit = db.session.commit()
  515. if commit == None:
  516. return 'OK'
  517. except Exception as e:
  518. pass
  519. return 'KO'
  520. @app.route('/providers/new', methods=['POST'])
  521. @resume_session
  522. def new_provider():
  523. """ Add provider """
  524. provider = Stock_providers(name=session[u'p_name'].decode('utf8'),
  525. address=session[u'p_address'].decode('utf8'),
  526. mail=session[u'p_mail'].decode('utf8'),
  527. url=session[u'p_url'].decode('utf8'),
  528. comment=session[u'p_comment'].decode('utf8'))
  529. try:
  530. db.session.add(provider)
  531. commit = db.session.commit()
  532. except Exception as e:
  533. db.session.rollback()
  534. print "[+] Error at new_provider:"
  535. print "------------------------------"
  536. print "%s" % e.message
  537. print "------------------------------"
  538. return 'KO'
  539. if commit != None:
  540. return 'KO'
  541. return 'OK'
  542. @app.route('/providers/delete/<provider_id>')
  543. @resume_session
  544. def delete_provider(provider_id):
  545. """ Delete provider """
  546. try:
  547. provider_id = int(provider_id)
  548. Stock_providers.query.filter_by(id=provider_id).delete()
  549. db.session.commit()
  550. except ValueError as e:
  551. return render_template('error.html', css=session[u'css']), 404
  552. except Exception as e:
  553. db.session.rollback()
  554. print "[+] Error at delete_provider:"
  555. print "------------------------------"
  556. print "%s" % e.message
  557. print "------------------------------"
  558. return providers()
  559. @app.route('/providers/update', methods=['POST'])
  560. @resume_session
  561. def search_providers():
  562. """ Display componants list """
  563. # search by reference
  564. like = '%s%s%s' % ('%', str(session[u'p_name']), '%')
  565. providers = Stock_providers.query.filter(Stock_providers.name.like(like))
  566. # search by address
  567. like = '%s%s%s' % ('%', str(session[u'p_address']), '%')
  568. providers = providers.filter(Stock_providers.address.like(like))
  569. # search by place
  570. like = '%s%s%s' % ('%', str(session[u'p_mail']),'%')
  571. providers = providers.filter(Stock_providers.mail.like(like))
  572. # search by place
  573. like = '%s%s%s' % ('%', str(session[u'p_url']),'%')
  574. providers = providers.filter(Stock_providers.url.like(like))
  575. # search by place
  576. like = '%s%s%s' % ('%', str(session[u'p_comment']),'%')
  577. providers = providers.filter(Stock_providers.comment.like(like))
  578. # Don't take 'all' and 'none' entry
  579. providers = providers.filter(Stock_providers.id > 2)
  580. # Pages calculation
  581. session[u'p_count'] = providers.count()
  582. session[u'p_pagecount'] = int(math.ceil(session[u'p_count'] / float(session[u'p_limit'])))
  583. session[u'p_page'] = int(math.ceil(float(float(session[u'p_offset']) + 1) / float(session[u'p_limit'])))
  584. if session[u'p_page'] > session[u'p_pagecount']:
  585. session[u'p_page'] = session[u'p_pagecount']
  586. session[u'p_offset'] = 0
  587. session[u'p_nexthop'] = session[u'p_offset'] + session[u'p_limit']
  588. if session[u'p_nexthop'] > session[u'p_count'] - 1:
  589. session[u'p_nexthop'] = int(session[u'p_offset'])
  590. session[u'p_prevhop'] = int(session[u'p_offset']) - session[u'p_limit']
  591. if session[u'p_prevhop'] < 0:
  592. session[u'p_prevhop'] = 0
  593. # Sorting
  594. sort = getattr(Stock_providers, session[u'p_sort'])
  595. if session[u'p_order'] == u'desc':
  596. sort = getattr(Stock_providers, session[u'p_sort']).desc()
  597. providers = providers.order_by(sort)
  598. # Applying offset
  599. providers = providers.offset(session[u'p_offset'])
  600. # Applying limit
  601. providers = providers.limit(session[u'p_limit'])
  602. # Get result
  603. providers = providers.all()
  604. response = app.make_response(render_template('result_providers.html',
  605. providers=providers,
  606. offset=session[u'p_offset'] ,
  607. nexthop=session[u'p_nexthop'],
  608. prevhop=session[u'p_prevhop'],
  609. page_count=session[u'p_pagecount'],
  610. page=session[u'p_page'],
  611. sort=session[u'p_sort'].decode('utf8'),
  612. order=session[u'p_order'].decode('utf8'),
  613. row_count=session[u'p_count']))
  614. sync_cookies(response, session)
  615. return response
  616. ########################################################################
  617. # Kits
  618. ########################################################################
  619. @app.route('/kits', methods=['GET', 'POST'])
  620. @resume_session
  621. def kits():
  622. return render_template('kits.html',
  623. name=session[u'k_name'].decode('utf8'),
  624. designation=session[u'k_designation'].decode('utf8'),
  625. css=session[u'css'])
  626. @app.route('/kits/<kit_id>')
  627. @resume_session
  628. def get_kit(kit_id):
  629. """ Edit kit """
  630. try:
  631. kit_id = int(kit_id)
  632. except ValueError as e:
  633. return render_template('error.html', css=session[u'css']), 404
  634. kit = Stock_kits.query.filter_by(id=kit_id).first()
  635. if kit:
  636. return render_template('kit.html', kit=kit, css=session[u'css'])
  637. return render_template('error.html', css=session[u'css']), 404
  638. @app.route('/kits/update/<kit_id>', methods=['POST'])
  639. @resume_session
  640. def update_kit(kit_id):
  641. """ Update kit field"""
  642. field = request.form['field']
  643. value = request.form['value']
  644. if field and value:
  645. try:
  646. kit = Stock_kits.query.filter_by(id=kit_id).first()
  647. setattr(kit, field, value)
  648. commit = db.session.commit()
  649. if commit == None:
  650. return 'OK'
  651. except Exception as e:
  652. pass
  653. return 'KO'
  654. @app.route('/kits/new', methods=['POST'])
  655. @resume_session
  656. def new_kit():
  657. """ Add kit """
  658. kit = Stock_kits(name=session[u'k_name'].decode('utf8'),
  659. designation=session[u'k_designation'].decode('utf8'))
  660. try:
  661. db.session.add(kit)
  662. commit = db.session.commit()
  663. except Exception as e:
  664. db.session.rollback()
  665. print "[+] Error at new_kit:"
  666. print "------------------------------"
  667. print "%s" % e.message
  668. print "------------------------------"
  669. return 'KO'
  670. if commit != None:
  671. return 'KO'
  672. return 'OK'
  673. @app.route('/kits/delete/<kit_id>')
  674. @resume_session
  675. def delete_kit(kit_id):
  676. """ Delete kit """
  677. try:
  678. kit_id = int(kit_id)
  679. Stock_kit_compositions.query.filter_by(kit_id=kit_id).delete()
  680. Stock_kits.query.filter_by(id=kit_id).delete()
  681. db.session.commit()
  682. except ValueError as e:
  683. return render_template('error.html', css=session[u'css']), 404
  684. except Exception as e:
  685. db.session.rollback()
  686. print "[+] Error at delete_kit:"
  687. print "------------------------------"
  688. print "%s" % e.message
  689. print "------------------------------"
  690. return kits()
  691. @app.route('/kits/update', methods=['POST'])
  692. @resume_session
  693. def search_kits():
  694. """ Display componants list """
  695. # search by name
  696. like = '%s%s%s' % ('%', str(session[u'k_name']), '%')
  697. kits = Stock_kits.query.filter(Stock_kits.name.like(like))
  698. # search by designation
  699. like = '%s%s%s' % ('%', str(session[u'k_designation']), '%')
  700. kits = kits.filter(Stock_kits.designation.like(like))
  701. # Pages calculation
  702. session[u'k_count'] = kits.count()
  703. session[u'k_pagecount'] = int(math.ceil(session[u'k_count'] / float(session[u'k_limit'])))
  704. session[u'k_page'] = int(math.ceil(float(float(session[u'k_offset']) + 1) / float(session[u'k_limit'])))
  705. if session[u'k_page'] > session[u'k_pagecount']:
  706. session[u'k_page'] = session[u'k_pagecount']
  707. session[u'k_offset'] = 0
  708. session[u'k_nexthop'] = session[u'k_offset'] + session[u'k_limit']
  709. if session[u'k_nexthop'] > session[u'k_count'] - 1:
  710. session[u'k_nexthop'] = int(session[u'k_offset'])
  711. session[u'k_prevhop'] = int(session[u'k_offset']) - session[u'k_limit']
  712. if session[u'k_prevhop'] < 0:
  713. session[u'k_prevhop'] = 0
  714. # Sorting
  715. sort = getattr(Stock_kits, session[u'k_sort'].decode('utf8'))
  716. if session[u'k_order'] == 'desc':
  717. sort = getattr(Stock_kits, session[u'k_sort'].decode('utf8')).desc()
  718. kits = kits.order_by(sort)
  719. # Applying offset
  720. kits = kits.offset(session[u'k_offset'])
  721. # Applying limit
  722. kits = kits.limit(session[u'k_limit'])
  723. # Get result
  724. kits = kits.all()
  725. for kit in kits:
  726. max_kit = get_max_kit(kit.id)
  727. setattr(kit, 'max_kit', max_kit)
  728. response = app.make_response(render_template('result_kits.html',
  729. kits=kits,
  730. offset=session[u'k_offset'] ,
  731. nexthop=session[u'k_nexthop'],
  732. prevhop=session[u'k_prevhop'],
  733. page_count=session[u'k_pagecount'],
  734. page=session[u'k_page'],
  735. sort=session[u'k_sort'].decode('utf8'),
  736. order=session[u'k_order'].decode('utf8'),
  737. row_count=session[u'k_count']))
  738. for key in session:
  739. response.set_cookie(key, value=str(session[key]))
  740. if key != 'session':
  741. print '[c]', key, session[key]
  742. return response
  743. @app.route('/kits/composition/<kit_id>', methods=['POST'])
  744. @resume_session
  745. def get_kit_composition(kit_id):
  746. kit_composition = []
  747. composition = Stock_kit_compositions.query.filter_by(kit_id=kit_id).with_entities(
  748. Stock_kit_compositions.componant_id,
  749. Stock_kit_compositions.quantity).all()
  750. # FIXME: Use join rather than this ugly work around
  751. # FIXME: Good luck !
  752. for c_componant in composition:
  753. componant = Stock_componants.query.filter_by(id=c_componant.componant_id).first()
  754. if componant:
  755. c = {u'id': componant.id,
  756. u'reference': componant.reference,
  757. u'designation': componant.designation,
  758. u'quantity': componant.quantity,
  759. u'needed': c_componant.quantity
  760. }
  761. kit_composition.append(c)
  762. max_kit = get_max_kit(kit_id)
  763. return render_template('kit_composition.html', kit_composition=kit_composition, max_kit=max_kit, kit_id=kit_id)
  764. @app.route('/kits/remove/<kit_id>/<componant_id>', methods=['GET'])
  765. @resume_session
  766. def remove_componant_from_kit(kit_id, componant_id):
  767. """ Remove componant from kit """
  768. try:
  769. kit_id = int(kit_id)
  770. Stock_kit_compositions.query.filter_by(kit_id=kit_id).filter_by(componant_id=componant_id).delete()
  771. db.session.commit()
  772. except ValueError as e:
  773. return render_template('error.html', css=session[u'css']), 404
  774. except Exception as e:
  775. db.session.rollback()
  776. print "[+] Error at remove_componant_from_kit:"
  777. print "------------------------------"
  778. print "%s" % e.message
  779. print "------------------------------"
  780. return get_kit(kit_id)
  781. @app.route('/kits/composition/add/<kit_id>', methods=['POST', 'GET'])
  782. @resume_session
  783. def add_componant_to_kit(kit_id):
  784. """ Add componant to kit """
  785. try:
  786. kit_id = int(kit_id)
  787. count = Stock_kit_compositions.query.filter_by(kit_id=kit_id, componant_id=session[u'kc_componant_id']).count()
  788. if count > 0:
  789. # Componant already in kit composition
  790. # => Updating with new quantity
  791. return update_kit_composition(kit_id)
  792. composition = Stock_kit_compositions(kit_id=kit_id,
  793. componant_id=session[u'kc_componant_id'],
  794. quantity=session[u'kc_quantity'])
  795. db.session.add(composition)
  796. commit = db.session.commit()
  797. except ValueError as e:
  798. return render_template('error.html', css=session[u'css']), 404
  799. except Exception as e:
  800. db.session.rollback()
  801. print "[+] Error at add_componant_to_kit:"
  802. print "------------------------------"
  803. print "%s" % e.message
  804. print "------------------------------"
  805. return 'KO'
  806. if commit != None:
  807. return 'KO'
  808. return 'OK'
  809. @app.route('/kits/composition/update/<kit_id>', methods=['GET', 'POST'])
  810. @resume_session
  811. def update_kit_composition(kit_id):
  812. """ Update componant quantity """
  813. try:
  814. kit_id = int(kit_id)
  815. composition = Stock_kit_compositions.query.filter_by(
  816. kit_id=kit_id, componant_id=session[u'kc_componant_id']).first()
  817. composition.quantity = session[u'kc_quantity']
  818. db.session.commit()
  819. except ValueError as e:
  820. return render_template('error.html', css=session[u'css']), 404
  821. except Exception as e:
  822. db.session.rollback()
  823. print "[+] Error at update_kit_composition:"
  824. print "------------------------------"
  825. print "%s" % e.message
  826. print "------------------------------"
  827. return get_kit(kit_id)
  828. ## Componants update result set
  829. @app.route('/kits/componants/update/<kit_id>', methods=['POST'])
  830. @resume_session
  831. def update_kit_componants(kit_id):
  832. """ Display componants list """
  833. # search by reference
  834. like = '%s%s%s' % ('%', str(session[u'kc_reference']), '%')
  835. componants = Stock_componants.query.filter(Stock_componants.reference.like(like))
  836. # search by designation
  837. like = '%s%s%s' % ('%', str(session[u'kc_designation']), '%')
  838. componants = componants.filter(Stock_componants.designation.like(like))
  839. # Applying limit
  840. componants = componants.limit(session[u'kc_limit'])
  841. # Get result
  842. componants = componants.all()
  843. response = app.make_response(render_template('result_kit_componants.html', kit_id=kit_id, componants=componants))
  844. sync_cookies(response, session)
  845. return response
  846. # Main #######################################
  847. if __name__ == '__main__':
  848. app.run(host='0.0.0.0')