diff --git a/src/OpenIntranet/handlers/__init__.py b/src/OpenIntranet/handlers/__init__.py
index 576da76f..adf4da0d 100644
--- a/src/OpenIntranet/handlers/__init__.py
+++ b/src/OpenIntranet/handlers/__init__.py
@@ -138,6 +138,11 @@ def get_current_user(self):
class BaseHandler(tornado.web.RequestHandler):
def prepare(self):
+
+ user_agent = self.request.headers["User-Agent"]
+ self.OIAPP = True if user_agent == 'OpenIntranetApp' else False
+ print("Iam running in app", self.OIAPP)
+
login = self.get_secure_cookie("user")
if login:
login = str(login, encoding="utf-8")
diff --git a/src/OpenIntranet/plugins/__init__.py b/src/OpenIntranet/plugins/__init__.py
index 47a28790..561b004e 100644
--- a/src/OpenIntranet/plugins/__init__.py
+++ b/src/OpenIntranet/plugins/__init__.py
@@ -55,17 +55,6 @@ def repl(f):
return layer
-'''
-@parametrized
-def perm_validator(fn, permissions = [], sudo=True):
- print("Validace opravneni.....")
- print(permissions, sudo, fn.__dict__)
- print(fn)
-
- return fn
-'''
-
-
def save_file(db, original_filename):
path = os.path.dirname(original_filename)
file = os.path.basename(original_filename)
@@ -116,6 +105,7 @@ def database_init():
def get_company_info(database):
return database.intranet.find_one({"_id": "company_info"}) or {}
+
def get_default_warehouse(database):
default = database.intranet.find_one({"_id": "default_warehouse"})
# TODO: umoznit uzivatelum mit vlastni vychozi sklad
@@ -213,6 +203,13 @@ class BaseHandler(tornado.web.RequestHandler):
role_module = []
def prepare(self):
+
+
+ user_agent = self.request.headers["User-Agent"]
+ self.in_app = True if 'Electron' in user_agent else False
+ print("Iam running in app", self.in_app)
+
+
login = self.get_secure_cookie("user")
if login:
login = str(login, encoding="utf-8")
@@ -256,6 +253,7 @@ def get_template_namespace(self):
ns = super(BaseHandler, self).get_template_namespace()
ns.update({
'intranet_title': tornado.options.options.intranet_name,
+ 'in_app': self.in_app,
})
return ns
diff --git a/src/OpenIntranet/plugins/android_reader_test.py b/src/OpenIntranet/plugins/android_reader_test.py
index de2f1703..bf25ede5 100644
--- a/src/OpenIntranet/plugins/android_reader_test.py
+++ b/src/OpenIntranet/plugins/android_reader_test.py
@@ -19,8 +19,8 @@ def get_plugin_handlers():
plugin_name = get_plugin_info()["name"]
return [
- (r'/%s' % plugin_name, hand_bi_home),
- (r'/%s/' % plugin_name, hand_bi_home),
+ (r'/{}'.format(plugin_name), hand_bi_home),
+ (r'/{}/'.format(plugin_name), hand_bi_home),
]
@@ -30,7 +30,7 @@ def get_plugin_info():
"entrypoints": [
{
"title": "Android čtečka",
- "url": "/payment",
+ "url": "/android_barcode",
"icon": "android",
}
],
@@ -40,7 +40,7 @@ def get_plugin_info():
class hand_bi_home(BaseHandler):
def get(self, data=None):
- roles = self.authorized(['andorid'], sudo=False)
+ roles = self.authorized(['andorid'], sudo=True)
print(">>>>>", roles)
self.render("android_barcode.home.hbs", title="UST intranet", parent=self)
diff --git a/src/OpenIntranet/plugins/property_manager/__init__.py b/src/OpenIntranet/plugins/property_manager/__init__.py
new file mode 100644
index 00000000..6357178e
--- /dev/null
+++ b/src/OpenIntranet/plugins/property_manager/__init__.py
@@ -0,0 +1,24 @@
+from .backend.property_manager import *
+#from .. import BaseHandler
+
+
+def get_plugin_handlers():
+ plugin_name = get_plugin_info()["name"]
+
+ return [
+ (r'/{}'.format(plugin_name), HomeHandler),
+ (r'/{}/'.format(plugin_name), HomeHandler),
+ ]
+
+
+def get_plugin_info():
+ return {
+ "name": "property_manager",
+ "entrypoints": [
+ {
+ "title": "Property manager",
+ "url": "/property_manager",
+ "icon": "bi-pc-display",
+ }
+ ]
+ }
diff --git a/src/OpenIntranet/plugins/property_manager/backend/__init__.py b/src/OpenIntranet/plugins/property_manager/backend/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/OpenIntranet/plugins/property_manager/backend/property_manager.py b/src/OpenIntranet/plugins/property_manager/backend/property_manager.py
new file mode 100644
index 00000000..852df8d3
--- /dev/null
+++ b/src/OpenIntranet/plugins/property_manager/backend/property_manager.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+import json
+from datetime import datetime, timedelta
+
+import bson.json_util
+import tornado
+import tornado.options
+from bson import ObjectId
+from dateutil.relativedelta import relativedelta
+from tornado.web import HTTPError
+
+from plugins import BaseHandler, password_hash
+from plugins import BaseHandlerOwnCloud
+from plugins.helpers import database_user as udb
+from plugins.helpers import str_ops
+from plugins.helpers.contract_generation import generate_contract
+from plugins.helpers.doc_keys import CONTRACT_DOC_KEYS
+from plugins.helpers.emails import generate_validation_token, generate_validation_message, send_email
+from plugins.helpers.exceptions import BadInputHTTPError, MissingInfoHTTPError, ForbiddenHTTPError
+from plugins.helpers.mdoc_ops import find_type_in_addresses, update_workspans_contract_id
+from plugins.helpers.owncloud_utils import get_file_url, generate_contracts_directory_path, \
+ generate_documents_directory_path
+from plugins.users.backend.helpers.api import ApiJSONEncoder
+
+
+
+"""
+Role:
+základní uživatel nemá speciální roli jelikož všichni jsou základními uživateli
+users-proprety_manager - spravce majetku
+users-sudo - Admin
+"""
+
+ROLE_SUDO = "users-sudo"
+
+class HomeHandler(BaseHandler):
+ def get(self):
+
+ self.render("../plugins/property_manager/frontend/property_manager.overview.hbs")
diff --git a/src/OpenIntranet/plugins/property_manager/frontend/property_manager.overview.hbs b/src/OpenIntranet/plugins/property_manager/frontend/property_manager.overview.hbs
new file mode 100644
index 00000000..2f4f62ce
--- /dev/null
+++ b/src/OpenIntranet/plugins/property_manager/frontend/property_manager.overview.hbs
@@ -0,0 +1,68 @@
+{% extends "base.hbs" %}
+{% block title %} | Produkce, uvod{% end %}
+{% block body %}
+
+{% import datetime %}
+
+
+
+ Home
+ Property manager
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Seznam majetku
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% end %}
diff --git a/src/OpenIntranet/plugins/store/data_import.py b/src/OpenIntranet/plugins/store/data_import.py
index a4d16f81..28250b95 100644
--- a/src/OpenIntranet/plugins/store/data_import.py
+++ b/src/OpenIntranet/plugins/store/data_import.py
@@ -51,10 +51,13 @@ def api_call(action, params, token, app_secret, show_header=False):
return json.loads(html);
-def mouser_api_call(action, mouser_key, body):
+def mouser_api_call(action, mouser_key, body = {}, method = "POST", debug = True):
api_url = "https://api.mouser.com/api/v1/" + action + "?apiKey=" + mouser_key
- response = request.Request(url=api_url, data=bytes(json.dumps(body), encoding='utf8'), headers={'Content-Type': 'application/json'}, method='POST' )
- response = json.loads(request.urlopen(response).read())['SearchResults']['Parts'][0]
+ print("Mouser api call", api_url)
+ print(body)
+ response = request.Request(url=api_url, data=bytes(json.dumps(body), encoding='utf8'), headers={'Content-Type': 'application/json'}, method=method )
+ response = json.loads(request.urlopen(response).read())
+ print(response)
return response
@@ -231,7 +234,7 @@ def get(self, component_id = None):
}
}
- product = mouser_api_call('search/partnumber', key, body)
+ product = mouser_api_call('search/partnumber', key, body)['SearchResults']['Parts'][0]
# self.write({'files': product_files['Data'], 'parameters': parameters['Data'], 'products': products})
self.render('store/store.api.importer.mouser.data.hbs',product=product)
@@ -302,7 +305,7 @@ def get(self):
}
}
- product = mouser_api_call('search/partnumber', key, body)
+ product = mouser_api_call('search/partnumber', key, body)['SearchResults']['Parts'][0]
# self.write({'files': product_files['Data'], 'parameters': parameters['Data'], 'products': products})
self.render('store/store.api.importer.mouser.data.hbs',product=product)
diff --git a/src/OpenIntranet/plugins/store/orders.py b/src/OpenIntranet/plugins/store/orders.py
index 2cd782dd..f3d79669 100644
--- a/src/OpenIntranet/plugins/store/orders.py
+++ b/src/OpenIntranet/plugins/store/orders.py
@@ -11,11 +11,16 @@
import bson
from bson import ObjectId
+from .orders_helper import *
+
def get_plugin_handlers():
plugin_name = 'store'
return [
(r'/{}/orders'.format(plugin_name), orders_home),
+ (r'/{}/order/(.*)/parameters/save'.format(plugin_name), order_parameters_save),
+ (r'/{}/order/(.*)/update_from_api'.format(plugin_name), order_update_from_api),
+ (r'/{}/order/(.*)'.format(plugin_name), order_edit),
(r'/{}/orders/orderlist'.format(plugin_name), orders_get_orderlist),
(r'/{}/orders/order_row'.format(plugin_name), orders_order_row),
(r'/{}/orders/order_row/select_supplier'.format(plugin_name), orders_order_setsupplier),
@@ -24,59 +29,118 @@ def get_plugin_handlers():
class orders_home(BaseHandler):
- def get(self):
- self.render("store/orders/orders.home.hbs")
+ def get(self):
+ self.render("store/orders/orders.home.hbs")
class orders_get_orderlist(BaseHandler):
- def get(self):
+ def get(self):
+
+ wait_list = list(self.mdb.stock_operation.aggregate([
+ {"$match": {"type": "order"}},
+ {"$sort": {"cid": 1}},
+ {"$lookup": {"from": "stock", "localField": "cid", "foreignField": "_id", "as": "component_info"}},
+ {"$group": {'_id': "$supplier", "order_rows": {"$push": "$$ROOT"}}},
+ {"$sort": {"_id": 1}}
+ ]))
+
+
+ order_list = list(self.mdb.orders.aggregate([
+
+ ]))
+
+
+ self.render("store/orders/orders.orderlist.hbs", order_list=order_list, wait_list=wait_list,
+ OrderStatusText=OrderStatusText)
+
+
+class order_edit(BaseHandler):
+ def get(self, order_id):
+ if order_id == 'new':
+ order_id = create_empty_order(self.mdb)
+ self.redirect('/store/order/{}'.format(order_id))
+
+ order_id = bson.ObjectId(order_id)
+ if order_id:
+ self.write("OK..."+str(order_id))
+ order_details = self.mdb.orders.aggregate([
+ {"$match": {'_id': order_id}},
+ ])
+ self.render('store/orders/order.edit.hbs', order = list(order_details)[0])
- wait_list = list(self.mdb.stock_operation.aggregate([
- {"$match": {"type": "order"}},
- {"$sort": {"cid": 1}},
- {"$lookup": {"from": "stock", "localField": "cid", "foreignField": "_id", "as": "component_info"}},
- {"$group": {'_id': "$supplier", "order_rows": {"$push": "$$ROOT"}}},
- {"$sort": {"_id": 1}}
- ]))
+class order_parameters_save(BaseHandler):
+ def post(self, order_id):
+ order_id = bson.ObjectId(order_id)
- self.render("store/orders/orders.orderlist.hbs", wait_list=wait_list)
+ supplier = self.get_argument('order_supplier', None)
+ identificator = self.get_argument('order_identificator', None)
+ self.mdb.orders.update_one({'_id': order_id}, {"$set":{'order_supplier': supplier, 'order_identificator': identificator}})
+ self.write("ok")
class orders_order_row(BaseHandler):
- def get(self):
- order_row = ObjectId(self.get_argument('order_row'))
+ def get(self):
+ order_row = ObjectId(self.get_argument('order_row'))
- row = list(self.mdb.stock_operation.aggregate([
- {"$match": {"_id": order_row}},
- {"$lookup": {"from": "stock", "localField": "cid", "foreignField": "_id", "as": "component_info"}},
- ]))
+ row = list(self.mdb.stock_operation.aggregate([
+ {"$match": {"_id": order_row}},
+ {"$lookup": {"from": "stock", "localField": "cid", "foreignField": "_id", "as": "component_info"}},
+ ]))
- self.render("store/orders/orders.componet_view.hbs", row=row[0])
+ self.render("store/orders/orders.componet_view.hbs", row=row[0])
class orders_order_setsupplier(BaseHandler):
- def post(self):
- order_row = ObjectId(self.get_argument('order_row'))
- supplier_i = int(self.get_argument('supplier'))
+ def post(self):
+ order_row = ObjectId(self.get_argument('order_row'))
+ supplier_i = int(self.get_argument('supplier'))
+
+ row = list(self.mdb.stock_operation.aggregate([
+ {"$match": {"_id": order_row}},
+ {"$lookup": {"from": "stock", "localField": "cid", "foreignField": "_id", "as": "component_info"}},
+ {"$project": {"_id":1, "component_info.supplier":1, "cid": 1}}
+ ]))[0]
+ supplier = row['component_info'][0]['supplier'][supplier_i]
+ out = self.mdb.stock_operation.update_one({'_id': row['_id']}, {"$set": {"supplier_id": supplier_i, "supplier": supplier['supplier'], "supplier_symbol": supplier['symbol'] }})
+
+ self.write(str(out))
+
+
+
+
+
+class order_update_from_api(BaseHandler):
+ def get(self, order_id):
+ order_id = bson.ObjectId(order_id)
+ api_data = order_update_data_from_api(self.mdb, order_id)
+ #api_data = json.loads(api_data)
+
+ ## TODO check if currency is CZK (or preset currency)
+
+ for i, item in enumerate(api_data.get('OrderLines', [])):
+ print(i, item)
+
+ row_data = {
+ 'order_id': order_id,
+ 'supplier_symbol': item.get('MouserPartNumber', None),
+ 'manufacturer_symbol': item.get('MfrPartNumber', None),
+ 'count': item.get('Quantity', None),
+ 'unit_price': item.get('UnitPrice', None),
+ 'api': True
+ }
- row = list(self.mdb.stock_operation.aggregate([
- {"$match": {"_id": order_row}},
- {"$lookup": {"from": "stock", "localField": "cid", "foreignField": "_id", "as": "component_info"}},
- {"$project": {"_id":1, "component_info.supplier":1, "cid": 1}}
- ]))[0]
- supplier = row['component_info'][0]['supplier'][supplier_i]
- out = self.mdb.stock_operation.update_one({'_id': row['_id']}, {"$set": {"supplier_id": supplier_i, "supplier": supplier['supplier'], "supplier_symbol": supplier['symbol'] }})
+ self.mdb.orders_items.insert_one(row_data)
- self.write(str(out))
+ self.write("OK")
class orders_add_to_orderlist(BaseHandler):
- def post(self):
+ def post(self):
- cid = ObjectId(self.get_argument('cid'))
- count = float(self.get_argument('count', 0))
- origin = self.get_argument('origin', None)
- description = self.get_argument('description', None)
+ cid = ObjectId(self.get_argument('cid'))
+ count = float(self.get_argument('count', 0))
+ origin = self.get_argument('origin', None)
+ description = self.get_argument('description', None)
- add_component_to_orderlist(self.mdb, self.logged, count=count, cid=cid, description=description, warehouse=self.get_warehouse()['_id'], origin=origin)
+ add_component_to_orderlist(self.mdb, self.logged, count=count, cid=cid, description=description, warehouse=self.get_warehouse()['_id'], origin=origin)
- self.write("OK")
+ self.write("OK")
diff --git a/src/OpenIntranet/plugins/store/orders_helper.py b/src/OpenIntranet/plugins/store/orders_helper.py
new file mode 100644
index 00000000..69b9ea1a
--- /dev/null
+++ b/src/OpenIntranet/plugins/store/orders_helper.py
@@ -0,0 +1,59 @@
+from enum import Enum
+import datetime
+import bson
+from .data_import import mouser_api_call
+import json
+
+
+class OrderStatus(Enum):
+ NEW = 1
+ READY_TO_REVIEW = 2
+ REVIEW_DONE = 3
+ ORDER_ORDERED = 4
+ ORDER_COMPLETE = 5
+
+OrderStatusText = ["Neznámý stav", "Nová objednávka", "Připraveno ke kontrole", "Kontrola splněna", "Objednávka odeslána", "Objednávka dokončena"]
+
+
+class OrderDirecton(Enum):
+ OUTCOMMING = 1
+ INCOMMING = 2
+
+
+def create_empty_order(db):
+ order_id = bson.ObjectId()
+ content = {
+ "_id": order_id,
+ "order_status" : OrderStatus.NEW.value,
+ "order_supplier" : None,
+ "order_supplier_info" : "",
+ "total_price" : "",
+ "order_identificator": "",
+ "payments" : [],
+ "items" : [],
+ "delivery": [],
+ "documents": [],
+ "date_created" : datetime.datetime.now(),
+ "date_send" : None,
+ "direction": OrderDirecton.OUTCOMMING,
+ }
+
+ db.orders.insert_one(content)
+ return order_id
+
+
+def order_update_data_from_api(db, order_id):
+ print("UPDATE ORDER DATA FROM API...")
+
+ order_data = dict(db.orders.find_one({'_id': order_id}))
+ print("ORDER DATA", order_data)
+ supplier = order_data.get('order_supplier', None)
+
+ if supplier.lower() == 'mouser':
+ key = db.intranet_plugins.find_one({'_id': 'store'})['data']['data_import']['mouser_api_key_account']
+ #data_import_info = self.mdb.intranet_plugins.find_one({'_id': 'store'})['data']['data_import']
+
+ body = {}
+
+ order_info = mouser_api_call('order/{}'.format(order_data.get('order_identificator')), key, body, method="GET")
+ return order_info
\ No newline at end of file
diff --git a/src/OpenIntranet/static/bootstrap-icons b/src/OpenIntranet/static/bootstrap-icons
index 25787cde..ec0e5863 160000
--- a/src/OpenIntranet/static/bootstrap-icons
+++ b/src/OpenIntranet/static/bootstrap-icons
@@ -1 +1 @@
-Subproject commit 25787cde29cb242261bc34714eda28c5350316a4
+Subproject commit ec0e5863162905fb35695e1c3612b6184ff476ce
diff --git a/src/OpenIntranet/templates/android_barcode.home.hbs b/src/OpenIntranet/templates/android_barcode.home.hbs
index 35b87588..4f911211 100644
--- a/src/OpenIntranet/templates/android_barcode.home.hbs
+++ b/src/OpenIntranet/templates/android_barcode.home.hbs
@@ -1,96 +1,65 @@
-{% extends "base.hbs" %}
+{# {% extends "base.hbs" %}
{% block title %}| TME catalog{%end%}
-{% block body %}
-
-
-
-
-
-
-
-
- IP:
-
Connect
-
Login
-
-
-
-
-
-
-
-
-
+
- window.addEventListener("connect", init, false);
+
+............
-
-
-{% end %}{# block body#}
+{#{% end %}#}{# block body#}
diff --git a/src/OpenIntranet/templates/base.hbs b/src/OpenIntranet/templates/base.hbs
index aeb4a401..7a522bf8 100644
--- a/src/OpenIntranet/templates/base.hbs
+++ b/src/OpenIntranet/templates/base.hbs
@@ -120,7 +120,8 @@
{%block head %}{%end%}
-
+
+{%if not in_app %}
{% block top-nav %}
@@ -131,7 +132,7 @@
-{% end %}
+{% end %}{% end %}
{% block body %} No content {%end%}
diff --git a/src/OpenIntranet/templates/store/orders/order.edit.hbs b/src/OpenIntranet/templates/store/orders/order.edit.hbs
new file mode 100644
index 00000000..8b9b113a
--- /dev/null
+++ b/src/OpenIntranet/templates/store/orders/order.edit.hbs
@@ -0,0 +1,227 @@
+{% extends "../../base.hbs" %}
+{% block title %}UST intranet | Objednávky {%end%}
+{% block body %}
+
+
+
Náhled objednávky
+
+ {{order}}
+
+
+
+ Tady bude seznam zaklanich parametru o objednavce. Kdy byla vytvorena, kdo je dodavatelem,
+
+
+
+ Mají tady být asi zase 3 sloupce. Další sloupce mají zobrazovat informace o dodávkách součástek (tj. jestli jsou už dodané nebo ještě ne. A popřípadě mít možnost to rozdělit na samostatné dodávky). Pak část, co se týče účetnictví (kolik chtějí zaplatit, kolik se zaplatilo, jakým způsobem, ..., jaký je přeplatek/nedoplatek). Měla by to být tabulka, kde bude typ/název dokladu. Pak bude sloupec bilance, který bude ukazovat kterým směrem je požadavek. A na spodním řádku bude součet. Tj. něco jako "Doplatek".
+
+ A pak bude samotný sloupec, který bude obsahovat soubory přiřazené k této objednávce. Tam se budou dávat objednávky, faktury, dodáky,... Popřípadě i nějaké strojové zpracoatelné soubory.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Faktura
+ 2020-10-10
+ - 1343 Czk
+ Ne
+
+
+ Platba
+ 2020-10-10
+ 1343 Czk
+ Ano (Fio)
+
+
+
+
+
+ Celková cena
+
+ 1343 Czk
+
+
+
+ Placeno
+
+ 1343 Czk
+
+
+
+ Bilance
+
+ 0 Czk
+
+
+
+
+
+
+
+
+
+
+
+
+ Název dokumentu
+ Datum vytvoření
+ Typ dokumentu
+
+
+ Objednávka
+ 2020-10-22
+ pdf
+
+
+ Faktura
+ 2020-10-22
+ pdf
+
+
+ Dodací list
+ 2020-10-22
+ pdf
+
+
+
+
+
+
+
+
+
+
+ Tady pak bude přehled položek v objednávce.
+ Bude zde název položky na faktuře. Pak bude sloupec, který říká, jestli je položka do skladu nebo ne (odkaz na součástku a pak na sáček, kam to bylo zařázené). Další slupec bude říkat počet objednaných komponent. Další sloupec bude obsahovat dodané počty ks.
+
+ Pokud nedojde k dodání celé položky najednou, tak při zapsání menšího čísla se vytvoří další položka, která bude rozdílem požadovaného počtu.
+
+
+
+
+
+
+ #
+
+
+ Položka (název dodavatele)
+
+
+ Celková cena (cena za ks)
+
+
+ Skladová položka/sáček
+
+
+ Objednaný počet (násobnost)
+
+
+ Dodáno
+
+
+ Stav
+
+
+
+
+
+
+
+ 1
+
+
+ SPS30-suuo (Senzor SPS30)
+
+
+ 2400 czk (24.0czk)
+
+
+ Bez skladové položky
+
+
+ 1000 ks (1x)
+
+
+ 100 ks
+
+
+ Dokončeno
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{%end%}
\ No newline at end of file
diff --git a/src/OpenIntranet/templates/store/orders/orders.home.hbs b/src/OpenIntranet/templates/store/orders/orders.home.hbs
index 4ab53113..f12a63fa 100644
--- a/src/OpenIntranet/templates/store/orders/orders.home.hbs
+++ b/src/OpenIntranet/templates/store/orders/orders.home.hbs
@@ -9,7 +9,6 @@
-
-
-