1. View, filter, and save Product Permutation. \n 2. Synchronised with Product Category page and all common functionality moved into base and base table css, js, and python files.
This commit is contained in:
Binary file not shown.
107
app.log
107
app.log
@@ -1,56 +1,51 @@
|
||||
Server Error: 500 Internal Server Error: The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
|
||||
Request: 127.0.0.1 GET http /login_callback?code=JMmHntUooZqn-PHB_xXhxkzf0lBMA6CcFQC1whmN23xUb&state=%2F Host: 127.0.0.1:5000
|
||||
|
||||
Connection: keep-alive
|
||||
|
||||
Pragma: no-cache
|
||||
|
||||
Cache-Control: no-cache
|
||||
|
||||
Dnt: 1
|
||||
|
||||
Upgrade-Insecure-Requests: 1
|
||||
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
|
||||
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
|
||||
Sec-Fetch-Site: cross-site
|
||||
|
||||
Sec-Fetch-Mode: navigate
|
||||
|
||||
Sec-Fetch-User: ?1
|
||||
|
||||
Sec-Fetch-Dest: document
|
||||
|
||||
Sec-Ch-Ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"
|
||||
|
||||
Sec-Ch-Ua-Mobile: ?0
|
||||
|
||||
Sec-Ch-Ua-Platform: "Windows"
|
||||
|
||||
Accept-Encoding: gzip, deflate, br, zstd
|
||||
|
||||
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
|
||||
|
||||
Cookie: session=.eJxtkG1rwjAQx79LwL7R9SG2aVooww2cCJvMMX1ZYnq10ZrUND5M2XdfKmNsMHLhwt3_cj_-V5S3hhnI2cFUfu6h9IoKZliXpZIcUIoeJrMZDquFv6mO7-PqeCrDCA2QhkJo4CY_aGFVlTFN6nkBjl3fniCNfN_3arUWMuesrleMb-3UQdff4taqCzjeyRPbYp8QKElFxVm6h9a90bhc7bzupbS4wL2GtlGyhdx8NJBxVYDDawHS5KLI1k-bD7N_eV4-Vm_ivJ_FeP56WUyWIwbT6WUunN-0Wbe-Nxz18NjGD7GtdMy29JfaabmyG-2Voug3WpWihj7smKidm3mZHXFubmX_evU5QHBuUBrEmETJMKSBGyUUUxLaDm91mRu1BWl9CUpK4pWPCcEkLjEDUuAoSRJKOUkIJauSch7E9ssvTeiOWA.ZumruQ.WqTz2NgZC14EQFnfvllT6CC2T3U
|
||||
|
||||
|
||||
|
||||
|
||||
Request data: b''
|
||||
Traceback: Traceback (most recent call last):
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\routing\user.py", line 91, in login_callback
|
||||
users, errors = datastore_user.get_many_user(user_filters, user)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\datastores\datastore_user.py", line 134, in get_many_user
|
||||
guid = Helper_DB_MySQL.create_guid()
|
||||
^^^^^^^^^^^^^^^
|
||||
NameError: name 'Helper_DB_MySQL' is not defined
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 1473, in wsgi_app
|
||||
response = self.full_dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Traceback: Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 1473, in wsgi_app
|
||||
response = self.full_dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 882, in full_dispatch_request
|
||||
rv = self.handle_user_exception(e)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask_cors\extension.py", line 178, in wrapped_function
|
||||
return cors_after_request(app.make_response(f(*args, **kwargs)))
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 880, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 865, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\controllers\store\product_category.py", line 57, in categories
|
||||
return render_template('pages/store/_product_categories.html', model = model)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\templating.py", line 150, in render_template
|
||||
return _render(app, template, context)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\templating.py", line 131, in _render
|
||||
rv = template.render(context)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\jinja2\environment.py", line 1304, in render
|
||||
self.environment.handle_exception()
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\jinja2\environment.py", line 939, in handle_exception
|
||||
raise rewrite_traceback_stack(source=source)
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\templates\pages\store\_product_categories.html", line 1, in top-level template code
|
||||
{% extends 'layouts/layout.html' %}
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\templates\layouts\layout.html", line 316, in top-level template code
|
||||
{% block page_body %}{% endblock %}
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\templates\pages\store\_product_categories.html", line 99, in block 'page_body'
|
||||
var currencies = {{ model.convert_list_objects_to_dict_json_by_attribute_key_default(model.access_levels) | tojson | safe }};
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\models\model_view_base.py", line 330, in convert_list_objects_to_dict_json_by_attribute_key_default
|
||||
return Model_View_Base.convert_list_objects_to_dict_json_by_attribute_key(list_objects, getattr(obj_class, obj_class.FLAG_NAME_ATTR_OPTION_VALUE))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\models\model_view_base.py", line 318, in convert_list_objects_to_dict_json_by_attribute_key
|
||||
return {getattr(obj, key): obj.to_json() for obj in list_objects}
|
||||
^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\business_objects\store\access_level.py", line 66, in to_json
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\lib\argument_validation.py", line 493, in input_bool
|
||||
raise ValueError(error_msg)
|
||||
ValueError: Invalid Access_Level.to_json <class 'bool'> argument active. Type = <class 'str'>. Value = 2
|
||||
|
||||
|
||||
107
app.log.1
107
app.log.1
@@ -1,4 +1,4 @@
|
||||
Exception on /store/products [GET]
|
||||
Exception on /store/categories [GET]
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 1473, in wsgi_app
|
||||
response = self.full_dispatch_request()
|
||||
@@ -15,89 +15,60 @@ Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 865, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\routing\store\product.py", line 40, in products
|
||||
filters.is_not_empty = filters.is_not_empty if arg_filter_is_not_empty is None else av.input_bool(arg_filter_is_not_empty, 'is_not_empty', 'filter')
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\pydantic\main.py", line 828, in __getattr__
|
||||
raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')
|
||||
AttributeError: 'Filters_Product' object has no attribute 'is_not_empty'
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\controllers\store\product_category.py", line 57, in categories
|
||||
return render_template('pages/store/_product_categories.html', model = model)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\templating.py", line 150, in render_template
|
||||
return _render(app, template, context)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\templating.py", line 131, in _render
|
||||
rv = template.render(context)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\jinja2\environment.py", line 1304, in render
|
||||
self.environment.handle_exception()
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\jinja2\environment.py", line 939, in handle_exception
|
||||
raise rewrite_traceback_stack(source=source)
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\templates\pages\store\_product_categories.html", line 1, in top-level template code
|
||||
{% extends 'layouts/layout.html' %}
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\templates\layouts\layout.html", line 316, in top-level template code
|
||||
{% block page_body %}{% endblock %}
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\templates\pages\store\_product_categories.html", line 99, in block 'page_body'
|
||||
var currencies = {{ model.convert_list_objects_to_dict_json_by_attribute_key_default(model.access_levels) | tojson | safe }};
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\models\model_view_base.py", line 330, in convert_list_objects_to_dict_json_by_attribute_key_default
|
||||
return Model_View_Base.convert_list_objects_to_dict_json_by_attribute_key(list_objects, getattr(obj_class, obj_class.FLAG_NAME_ATTR_OPTION_VALUE))
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\models\model_view_base.py", line 318, in convert_list_objects_to_dict_json_by_attribute_key
|
||||
return {getattr(obj, key): obj.to_json() for obj in list_objects}
|
||||
^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\business_objects\store\access_level.py", line 66, in to_json
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\lib\argument_validation.py", line 493, in input_bool
|
||||
raise ValueError(error_msg)
|
||||
ValueError: Invalid Access_Level.to_json <class 'bool'> argument active. Type = <class 'str'>. Value = 2
|
||||
Server Error: 500 Internal Server Error: The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
|
||||
Request: 127.0.0.1 GET http /store/products? Host: 127.0.0.1:5000
|
||||
Request: 127.0.0.1 GET http /store/categories? Host: 127.0.0.1:5000
|
||||
|
||||
Connection: keep-alive
|
||||
|
||||
Pragma: no-cache
|
||||
|
||||
Cache-Control: no-cache
|
||||
|
||||
|
||||
Sec-Ch-Ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"
|
||||
|
||||
Sec-Ch-Ua-Mobile: ?0
|
||||
|
||||
Sec-Ch-Ua-Platform: "Windows"
|
||||
|
||||
Dnt: 1
|
||||
|
||||
|
||||
Upgrade-Insecure-Requests: 1
|
||||
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
|
||||
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
|
||||
Sec-Fetch-Site: same-origin
|
||||
|
||||
Sec-Fetch-Mode: navigate
|
||||
|
||||
Sec-Fetch-User: ?1
|
||||
|
||||
Sec-Fetch-Dest: document
|
||||
|
||||
Referer: http://127.0.0.1:5000/store/products
|
||||
|
||||
Accept-Encoding: gzip, deflate, br, zstd
|
||||
|
||||
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
|
||||
|
||||
Cookie: session=.eJytVlmvqzgS_iutSN1PnXPB7EdqzWQFcgJJSFhfIseGYLYQlgTovv99TM6de_uhZ5NGCsF2FVVfudbfJ7Bt4ltF6hDbdVhN3n-fIFicIc5Jca6bWxVO3puqDX_903H7Yvw8DXNIssn7JMRPWOG3nGCchc2tqHPSxH-_jtQ3dMsnv04iUtVNAXMqcHIKMe7pGcFn1FZVWKD-jMMItlkzeS_aLHuRqvBKbsVfED4BsN_X59EIhsp9vf8QBRlcFAHJioAZBUrMBbJMFEajwvr8Qnx-hBWJSIgn7xHM6vBFIQXKWhziszM7_dD6aScl121JVf3Z-Lqtvhlk_NPu6XE0fPKV3lddRefmloYFpQMlwgoQsYKlSxRCSQKcKCGJh5iHUBIVXpAlxIkshdh-cwNEKKzr7xLCfhNfVER2ZJNCTyfbxSa75Ma4nxuJDSzGNHXyJNAzBz25EahZDNIMcdsraeD5zaXAMRz0p5kEWZAEt52a8RcisKgXYuxZN2MhJBfAPPSCeXvze4tKEYTwmU3D5zp7c4SZLjNFgfY8-gjvHnuYabF2nJVyG-RcftMz42oEkvshrnMju1PU_bkqJC3z5i1MdprqYeuYRPLixBtp1xIQA8Xp-dapiMF2q3XBR7DyhLpr0E7Wc0U_SbVnFpqqM4_iHkBj734cVW7rFlwjHLzNw_WZM75Ws6WzUE6mVZ8f25PTbk9q90xdrdib7sbkhZnk5Iv1dGb46v1cwKMpbhqIV7t-Olsqnn44cz2zFstD_vHs9oqg9OFB2HN8L2SsxXe4q4fkYzhraz0Jmfn8ZkgztLA0rXkmDNsN-5pM8-3DkvIti_VcXnv3_rhke1GlydQaInPyuhvjMqudLekflrk8V7IVgT1bK9usW5sw3byFSz-WpuG534rKND3C3f3jsZjRMAi7klRhfYY0BFkJ8JLCA4n7cU5oUMgizzCvLPiLKDnag86aRK_1whLQQhf1tPScBd3nTRmM-8J5hF5gWynPX5LNI9CurJOut8Y6Zq1-o7xRYS10zeqSr5vgSD_InRSDdR8shAa6VnpRHeYChOHiZgx8CRbii2uPyrNAwzHKDy2lpYHaZVhVWgTYEqvxLABsDN1n6wOlGUMWqVmCNaf_1BEzWJsPOyI_aGgWKF8D37NiRD7D0_eCGKvrfjvYQ7A0cyM5MMYSp-aJGgt83lT93gRmbCwRbw4WCZY-s-cMxVxen5tCV5CK8mDJ3rBmPVFvD4ej3VuEPrmZ0nT4cypkRkp15WvG9zbD5rRRA_fQIlUoRszYm6cUVxaslRiPl5noT4qlMZbXxkgC20hWojHQ56S3u6XRu6Mjcqfx3awe0zNwLY7KTbc5WwaqVQee9bgUZgOp_oOKX3zb3Hxcjj--87ggQ3mWQ9dJ9aTMfbcbguP_IeWpPb43yqS4GHwPPas7pax3APEJenF3GuhNZWvRSWPv4K6zY1qKdp6OJaj0vQPZJSuO2s593rkx4uXHgDNOqDeXiDGGK2f01M-cQ0YdVBcDl3PZTGzeyHXBdA1-d3JSY5nF5jAn_mn1DHInf8UGyF64fC4GFpupgeM8Ajue23lTBKqwN_Ly6J7i1k07YKhKYuSrEVdL4zJ5xVNyYEM1digtDoY5H6hpb3M4NtR4NZa62lxb5-BKHJ-5qoVdajZnlPuzVazqW-MRdyezCjSVVfjQFnay2OaaKUXA6QU9AF2xVze7JPUUwlv2gLj99n7XpG2UwvlSjqMqR_gBBj9sTZNfzbIbK88Jm8b6ScmwLboPgDwP28vzAe6Jve-rbLbWzdPUkjeLsJLSSJ0zRGkS3lxZ9rXNHd2XzMtuhYDdAbT1uzTxC6yWxqoaem56MUV1WGhXJlJMf1668VTeldou1ARNP2ERHmc7jdSYd4J0teM6Ge27w95p5_e5EIG2STucgGNM7BLuNGjNHwuwmw5G0JRbrduLW8VAZ24mrKKj5YNl1qvk3q8ObHe_xayr6i6u4xKtMCPx7JXWrxrdyrEz0v-C4J_K6haRLPzpc174dfIqWOemf_HMQ1jRpvfZ-0gR3V79r6XNeXJVk765m4a7iI-ku-8kYB0GR3NnMNxsaH5P_pcR5F-0flpSv9VYnpPHGku-F11G-jyoa6ogbpqyfv_yBYePafGEKWBEMYzEWCZd8dbWb6_pY1T1her6Nhj8Z1AFQem_Yx5ZbgUa6bzQxTZzg1emwwQcn5CJl5RcEtS046D2HWH9dq3gAzawesH5XH4ROMxFgOcZCQtAkCKZj4CE4Ggjf8Ei_7f6N15mfql-K6-_4N9esn7mZj-DNf0hXPywj-4_RdZ0FeK3snh5nIwOQ91D9dehfQu1mZVecbEDieXLRbB9MDcE4MjYXv6bWa0tMWzoNDY6YwIYwE8ZeQrEE2DfOfadBW8yB4LJ169f_wFsnZ0r.Zsz0IQ.CsqbE-G2jF9oYmUiZKS36HfeRw4
|
||||
|
||||
|
||||
|
||||
|
||||
Request data: b''
|
||||
Traceback: Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 1473, in wsgi_app
|
||||
response = self.full_dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 882, in full_dispatch_request
|
||||
rv = self.handle_user_exception(e)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask_cors\extension.py", line 178, in wrapped_function
|
||||
return cors_after_request(app.make_response(f(*args, **kwargs)))
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 880, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 865, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\routing\store\product.py", line 40, in products
|
||||
filters.is_not_empty = filters.is_not_empty if arg_filter_is_not_empty is None else av.input_bool(arg_filter_is_not_empty, 'is_not_empty', 'filter')
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\pydantic\main.py", line 828, in __getattr__
|
||||
raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')
|
||||
AttributeError: 'Filters_Product' object has no attribute 'is_not_empty'
|
||||
|
||||
Exception on /login_callback [GET]
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\routing\user.py", line 91, in login_callback
|
||||
users, errors = datastore_user.get_many_user(user_filters, user)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\datastores\datastore_user.py", line 134, in get_many_user
|
||||
guid = Helper_DB_MySQL.create_guid()
|
||||
^^^^^^^^^^^^^^^
|
||||
NameError: name 'Helper_DB_MySQL' is not defined
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 1473, in wsgi_app
|
||||
|
||||
52
app.log.2
Normal file
52
app.log.2
Normal file
@@ -0,0 +1,52 @@
|
||||
Request: 127.0.0.1 GET http /store/categories? Host: 127.0.0.1:5000
|
||||
|
||||
Connection: keep-alive
|
||||
|
||||
Pragma: no-cache
|
||||
|
||||
Cache-Control: no-cache
|
||||
|
||||
Sec-Ch-Ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"
|
||||
|
||||
Sec-Ch-Ua-Mobile: ?0
|
||||
|
||||
Sec-Ch-Ua-Platform: "Windows"
|
||||
|
||||
Dnt: 1
|
||||
|
||||
Upgrade-Insecure-Requests: 1
|
||||
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
|
||||
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
|
||||
Sec-Fetch-Site: same-origin
|
||||
|
||||
Sec-Fetch-Mode: navigate
|
||||
|
||||
Sec-Fetch-User: ?1
|
||||
|
||||
Sec-Fetch-Dest: document
|
||||
|
||||
Referer: http://127.0.0.1:5000/store/categories
|
||||
|
||||
Accept-Encoding: gzip, deflate, br, zstd
|
||||
|
||||
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
|
||||
|
||||
Cookie: session=.eJytVlnTqkgS_SsdRnQ_tV5WgS_ixgyKoAioyP5iQBXIDrIp9Nz_PoXf7b790LNFTIQLVZlknqw8mZW_Lfy-i6smaUNotmGz-PhtAfzy5sMiKW9tVzXh4qNr-vDXP233b8XP3bDwk3zxsQjh02_gqkggzMOuKtsi6eK_32fpClTF4tdFlDRtV_oFMrgwQghHtJfAG-ibJizBeINh5Pd5t_go-zx_i5rwnlTlXwg-AeB_PN_mIDBk9_3_jzXNEgFHA5ajIcb5DBb4OBaF0eywvb0R34awSaIkhIuPyM_b8C1JSpD3MIQ3izd-eP2ME4nbvkau_hx82zffA1J_j3t5nQNffEPn1TbRrauysETyiGQIwFI050MqBCzJQJZZQ5JiYQQ53McjjgoRYogg9t_T4AMQtu0fFsJRjgMJJKdEznznkChbOQ8KdV5v1NQkdEzTDskz8R1tOqRV4u91DOzVtTJymee4XVDC2J8OTy31ci_1qpOUU0FC42CkY-jolbql04DAhkOJrVZ4n9zgPW_UttIjONSrmOV8heXutnKHMDvZjkRs4HXq8UySz1WP1W5xZ578UPS15lgaOHpFFrG3K2-KwrkYwUYfDLspeyqv24yIb0dSiGzHMXL2pGwd7jCFnJDLRXxWjnz5jGi60A1XXPO3IfBUoTT6uN_YJWljzLLFqaOQtnbKBDl8SntNI240lsbTeCJt3uaNc6B4JXO-hcNdleCVnKjWL4FYAckglMEQlmFaVje-60VR3lmVIk92l7g7esc1k8jDfkjOHhsMBK33ob08W8fA7yMI9zUjMolNWGIlc85u34mH55otmlTcFOmpF9fPnhwjke8LhhP7ZVNuhh31YEnV5ze2fIkC6wLxQ2zuy3tXPTi2bBrBXPlKoC1v2qSbxnEa6Gc7HXfiBdEgfNVJE7Y3H1EQZ4j1mmFxjvmxnyBSsGsKw95V8BcsuZrTAdeSQ3sodRpsD-tDVjvWFq2LrvbmdWkNoeOZekZRQSoP3v6OW5moqGKM66PMrZCx3re1JijEzruiFworg4Q4elu68209CyQLCwh6Cuwc89-G6Tiwzdl57u1hDIpLj2SZJ71yKHE9IPAaSjHvEXjs28_eJbhupiyQ8hTurfHTR4zB_WY6JeyAqFmCQiRcR49B8klP1_FiKImjMpmTJ2iFml4wVYCZZqBgCZfSJHfUCC1WBUChU008wcXOpMppwv0plwcOSKDwBLyCe_0JRnO6XM1RT9C30DJUDn8uhVzNkK9CxFxHnmRDljz70gOJLmfM0NlkCFfuiVwM58NMD0-EpVOFrFMNaKqGu9aEbK0ZWa9O6sueE1FYnWvn7Vyenq2TyG6mFHjtSXrrOfoQlFrnI_8XCb71lEIbguuP9xzSy0GRF75tZYe0Llz7NXnX_0PJo3hcZ7aJcGHwETr6y8hw50LEhu_EL2NCJ5WLayuLnYst5tesXptFNreg2nUuySndkWrq4idjR6kCP-OlZsKpBhi1FOVjuj_VLcozaSWzD-QL84UNq6UmpRYHWrNV6mRYmSrksTZtEtfYPb3CKt7cIPI3LheTNb3USm9XK1bOHS5OLOp7y7KMjQPxOtYn62yQULETbMbVI16mbz6VGa06snDNXp6ZiQ4wX74vWkSwi8m51WknEB7azjhfdEZ1sshI11ePfSn8stg8z4oRUWVvc6_lut0nU6w3BHu_nBrRiqPNqDCipeoPPF9uAvzxkp7OVt7jdjatRfPU9Nchf9Giae8f2SsDcjcJYSIwtAcFEssTd8zrTW09judpixsysSzNi8a5nSzxugbwzbKNNl1p5B2w475NFUehT4o3iNSJBn7U2A8KkiDa8lUaHA2dwCKW3IZSLp12hfPisfLSu5ozyJUXkBJqe2FtBUe-6KuXR98ft93oHl-vssBuo8uMB2W3g8dk_6qOPrZLzBIfyO4B2tSJNog8rM7uL7Vwx7xj4tSg4ZXtwYwmpwOvitlXN_y5t6txT06uU16WXLh8ov7Vgqqeb0b0Wybwp7qpoiQPf_qcF35dvBvWrRvfOpvQb9Cl93n3JWVUve-_Hl3Oi7uUjt1DU-1tfE1ejxND6JfJ2tu8H8oyqu_F_zKC_IurH7XU7z2WYNh3Q_296dIc_rnRtshB3HV1-_HlCwyHZfn0MwJbr8NoHbPJq1z17eo9fcyuviBf3weD_wyqTED275RnlaoEs3zk8GYrK67O2w_Fi80h389HXSeg6-dB7Q-E7ere-IPf-c0bzufjF5qEZERQFMZAmqCZiKUiggE-xrAMFcA19bf2K8VivzRf6_sv8Ovb1s8k_zMhog-A5Y_40PrTZIueQriqy_uc8WROGNioYnuH8tG67fnXTuhNE7Ofni_Rp9Pz6C1nxT74b2a1voZ-h6axORkLAiOoJcYtccbA1x8U90FzK5LEvcW3b9_-CTbvo8I.ZumzNg.3EndhjI8QnbotIPyN-mo04fvFAg
|
||||
|
||||
|
||||
|
||||
|
||||
Request data: b''
|
||||
Traceback: Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 1473, in wsgi_app
|
||||
response = self.full_dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 882, in full_dispatch_request
|
||||
rv = self.handle_user_exception(e)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask_cors\extension.py", line 178, in wrapped_function
|
||||
return cors_after_request(app.make_response(f(*args, **kwargs)))
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
83
app.log.3
Normal file
83
app.log.3
Normal file
@@ -0,0 +1,83 @@
|
||||
Request: 127.0.0.1 GET http /store/categories? Host: 127.0.0.1:5000
|
||||
|
||||
Connection: keep-alive
|
||||
|
||||
Pragma: no-cache
|
||||
|
||||
Cache-Control: no-cache
|
||||
|
||||
Sec-Ch-Ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"
|
||||
|
||||
Sec-Ch-Ua-Mobile: ?0
|
||||
|
||||
Sec-Ch-Ua-Platform: "Windows"
|
||||
|
||||
Dnt: 1
|
||||
|
||||
Upgrade-Insecure-Requests: 1
|
||||
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
|
||||
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
|
||||
|
||||
Sec-Fetch-Site: same-origin
|
||||
|
||||
Sec-Fetch-Mode: navigate
|
||||
|
||||
Sec-Fetch-User: ?1
|
||||
|
||||
Sec-Fetch-Dest: document
|
||||
|
||||
Referer: http://127.0.0.1:5000/store/categories
|
||||
|
||||
Accept-Encoding: gzip, deflate, br, zstd
|
||||
|
||||
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
|
||||
|
||||
Cookie: session=.eJytVlnTqkgS_SsdRnQ_tV5WgS_ixgyKoAioyP5iQBXIDrIp9Nz_PoXf7b790LNFTIQLVZlknqw8mZW_Lfy-i6smaUNotmGz-PhtAfzy5sMiKW9tVzXh4qNr-vDXP233b8XP3bDwk3zxsQjh02_gqkggzMOuKtsi6eK_32fpClTF4tdFlDRtV_oFMrgwQghHtJfAG-ibJizBeINh5Pd5t_go-zx_i5rwnlTlXwg-AeB_PN_mIDBk9_3_jzXNEgFHA5ajIcb5DBb4OBaF0eywvb0R34awSaIkhIuPyM_b8C1JSpD3MIQ3izd-eP2ME4nbvkau_hx82zffA1J_j3t5nQNffEPn1TbRrauysETyiGQIwFI050MqBCzJQJZZQ5JiYQQ53McjjgoRYogg9t_T4AMQtu0fFsJRjgMJJKdEznznkChbOQ8KdV5v1NQkdEzTDskz8R1tOqRV4u91DOzVtTJymee4XVDC2J8OTy31ci_1qpOUU0FC42CkY-jolbql04DAhkOJrVZ4n9zgPW_UttIjONSrmOV8heXutnKHMDvZjkRs4HXq8UySz1WP1W5xZ578UPS15lgaOHpFFrG3K2-KwrkYwUYfDLspeyqv24yIb0dSiGzHMXL2pGwd7jCFnJDLRXxWjnz5jGi60A1XXPO3IfBUoTT6uN_YJWljzLLFqaOQtnbKBDl8SntNI240lsbTeCJt3uaNc6B4JXO-hcNdleCVnKjWL4FYAckglMEQlmFaVje-60VR3lmVIk92l7g7esc1k8jDfkjOHhsMBK33ob08W8fA7yMI9zUjMolNWGIlc85u34mH55otmlTcFOmpF9fPnhwjke8LhhP7ZVNuhh31YEnV5ze2fIkC6wLxQ2zuy3tXPTi2bBrBXPlKoC1v2qSbxnEa6Gc7HXfiBdEgfNVJE7Y3H1EQZ4j1mmFxjvmxnyBSsGsKw95V8BcsuZrTAdeSQ3sodRpsD-tDVjvWFq2LrvbmdWkNoeOZekZRQSoP3v6OW5moqGKM66PMrZCx3re1JijEzruiFworg4Q4elu68209CyQLCwh6Cuwc89-G6Tiwzdl57u1hDIpLj2SZJ71yKHE9IPAaSjHvEXjs28_eJbhupiyQ8hTurfHTR4zB_WY6JeyAqFmCQiRcR49B8klP1_FiKImjMpmTJ2iFml4wVYCZZqBgCZfSJHfUCC1WBUChU008wcXOpMppwv0plwcOSKDwBLyCe_0JRnO6XM1RT9C30DJUDn8uhVzNkK9CxFxHnmRDljz70gOJLmfM0NlkCFfuiVwM58NMD0-EpVOFrFMNaKqGu9aEbK0ZWa9O6sueE1FYnWvn7Vyenq2TyG6mFHjtSXrrOfoQlFrnI_8XCb71lEIbguuP9xzSy0GRF75tZYe0Llz7NXnX_0PJo3hcZ7aJcGHwETr6y8hw50LEhu_EL2NCJ5WLayuLnYst5tesXptFNreg2nUuySndkWrq4idjR6kCP-OlZsKpBhi1FOVjuj_VLcozaSWzD-QL84UNq6UmpRYHWrNV6mRYmSrksTZtEtfYPb3CKt7cIPI3LheTNb3USm9XK1bOHS5OLOp7y7KMjQPxOtYn62yQULETbMbVI16mbz6VGa06snDNXp6ZiQ4wX74vWkSwi8m51WknEB7azjhfdEZ1sshI11ePfSn8stg8z4oRUWVvc6_lut0nU6w3BHu_nBrRiqPNqDCipeoPPF9uAvzxkp7OVt7jdjatRfPU9Nchf9Giae8f2SsDcjcJYSIwtAcFEssTd8zrTW09judpixsysSzNi8a5nSzxugbwzbKNNl1p5B2w475NFUehT4o3iNSJBn7U2A8KkiDa8lUaHA2dwCKW3IZSLp12hfPisfLSu5ozyJUXkBJqe2FtBUe-6KuXR98ft93oHl-vssBuo8uMB2W3g8dk_6qOPrZLzBIfyO4B2tSJNog8rM7uL7Vwx7xj4tSg4ZXtwYwmpwOvitlXN_y5t6txT06uU16WXLh8ov7Vgqqeb0b0Wybwp7qpoiQPf_qcF35dvBvWrRvfOpvQb9Cl93n3JWVUve-_Hl3Oi7uUjt1DU-1tfE1ejxND6JfJ2tu8H8oyqu_F_zKC_IurH7XU7z2WYNh3Q_296dIc_rnRtshB3HV1-_HlCwyHZfn0MwJbr8NoHbPJq1z17eo9fcyuviBf3weD_wyqTED275RnlaoEs3zk8GYrK67O2w_Fi80h389HXSeg6-dB7Q-E7ere-IPf-c0bzufjF5qEZERQFMZAmqCZiKUiggE-xrAMFcA19bf2K8VivzRf6_sv8Ovb1s8k_zMhog-A5Y_40PrTZIueQriqy_uc8WROGNioYnuH8tG67fnXTuhNE7Ofni_Rp9Pz6C1nxT74b2a1voZ-h6axORkLAiOoJcYtccbA1x8U90FzK5LEvcW3b9_-CTbvo8I.ZumzNg.3EndhjI8QnbotIPyN-mo04fvFAg
|
||||
|
||||
|
||||
|
||||
|
||||
Request data: b''
|
||||
Traceback: Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 1473, in wsgi_app
|
||||
response = self.full_dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 882, in full_dispatch_request
|
||||
rv = self.handle_user_exception(e)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask_cors\extension.py", line 178, in wrapped_function
|
||||
return cors_after_request(app.make_response(f(*args, **kwargs)))
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 880, in full_dispatch_request
|
||||
rv = self.dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 865, in dispatch_request
|
||||
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\controllers\store\product_category.py", line 56, in categories
|
||||
model = Model_View_Store_Product_Category(form_filters)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\models\model_view_store_product_category.py", line 46, in __init__
|
||||
self.access_levels = self.get_many_access_level(Filters_Access_Level())
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\models\model_view_base.py", line 299, in get_many_access_level
|
||||
access_levels, errors = DataStore_Base.get_many_access_level(filters)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\OneDrive\Documents\Programming\Visual Studio 2022\PARTS_Web\app\datastores\datastore_base.py", line 214, in get_many_access_level
|
||||
av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
NameError: name 'Filters_Access_Level' is not defined
|
||||
|
||||
Exception on /store/categories [GET]
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 1473, in wsgi_app
|
||||
response = self.full_dispatch_request()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask\app.py", line 882, in full_dispatch_request
|
||||
rv = self.handle_user_exception(e)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\edwar\AppData\Local\Programs\Python\Python312\Lib\site-packages\flask_cors\extension.py", line 178, in wrapped_function
|
||||
return cors_after_request(app.make_response(f(*args, **kwargs)))
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
25
app.py
25
app.py
@@ -37,15 +37,15 @@ from datastores.datastore_store_base import DataStore_Store
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
"""
|
||||
from routing.core import routes_core
|
||||
from routing.legal import routes_legal
|
||||
from routing.store.store import routes_store
|
||||
from routing.store.product import routes_store_product
|
||||
from routing.store.product_category import routes_store_product_category
|
||||
from routing.store.product_permutation import routes_store_product_permutation
|
||||
from routing.store.stock_item import routes_store_stock_item
|
||||
from routing.store.supplier import routes_store_supplier
|
||||
from routing.user import routes_user
|
||||
from controllers.core import routes_core
|
||||
from controllers.legal import routes_legal
|
||||
from controllers.store.store import routes_store
|
||||
from controllers.store.product import routes_store_product
|
||||
from controllers.store.product_category import routes_store_product_category
|
||||
from controllers.store.product_permutation import routes_store_product_permutation
|
||||
from controllers.store.stock_item import routes_store_stock_item
|
||||
from controllers.store.supplier import routes_store_supplier
|
||||
from controllers.user import routes_user
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session
|
||||
# from flask_appconfig import AppConfig
|
||||
@@ -131,3 +131,10 @@ app.register_blueprint(routes_store_product_permutation)
|
||||
app.register_blueprint(routes_store_stock_item)
|
||||
app.register_blueprint(routes_store_supplier)
|
||||
app.register_blueprint(routes_user)
|
||||
|
||||
|
||||
|
||||
@app.template_filter('console_log')
|
||||
def console_log(value):
|
||||
print(value)
|
||||
return value
|
||||
Binary file not shown.
Binary file not shown.
BIN
business_objects/__pycache__/unit_measurement.cpython-312.pyc
Normal file
BIN
business_objects/__pycache__/unit_measurement.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
59
business_objects/base.py
Normal file
59
business_objects/base.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Base Business Object
|
||||
|
||||
Description:
|
||||
Abstract business object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from extensions import db
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Base():
|
||||
ATTR_ID_ACCESS_LEVEL: ClassVar[str] = 'id_access_level'
|
||||
ATTR_ID_CURRENCY: ClassVar[str] = 'id_currency'
|
||||
ATTR_ID_DELIVERY_REGION: ClassVar[str] = 'id_delivery_region'
|
||||
ATTR_ID_USER: ClassVar[str] = 'id_user'
|
||||
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = 'access_level_required'
|
||||
FLAG_ACTIVE: ClassVar[str] = 'active'
|
||||
FLAG_CAN_ADMIN: ClassVar[str] = 'can_admin'
|
||||
FLAG_CAN_EDIT: ClassVar[str] = 'can_edit'
|
||||
FLAG_CAN_VIEW: ClassVar[str] = 'can_view'
|
||||
FLAG_CODE: ClassVar[str] = 'code'
|
||||
FLAG_DESCRIPTION: ClassVar[str] = 'description'
|
||||
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display_order'
|
||||
FLAG_GUID: ClassVar[str] = 'guid'
|
||||
FLAG_IS_NOT_EMPTY: ClassVar[str] = 'is_not_empty'
|
||||
# FLAG_KEY_PRIMARY: ClassVar[str] = 'key_primary'
|
||||
FLAG_NAME: ClassVar[str] = 'name'
|
||||
FLAG_NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'NAME_ATTR_OPTION_TEXT'
|
||||
FLAG_NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'NAME_ATTR_OPTION_VALUE'
|
||||
FLAG_NAME_SINGULAR: ClassVar[str] = 'name_singular'
|
||||
FLAG_NAME_PLURAL: ClassVar[str] = 'name_plural'
|
||||
FLAG_PRIORITY: ClassVar[str] = 'priority'
|
||||
FLAG_ROWS: ClassVar[str] = 'rows'
|
||||
FLAG_SYMBOL: ClassVar[str] = 'symbol'
|
||||
FLAG_URL: ClassVar[str] = 'url'
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'name-attribute-option-text'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'name-attribute-option-value'
|
||||
|
||||
@classmethod
|
||||
def output_bool(cls, value):
|
||||
return av.input_bool(value, f'{cls.__name__} bool attribute', f'{cls.__name__}.output_bool')
|
||||
@staticmethod
|
||||
def convert_list_objects_to_list_options(objects):
|
||||
return [object.to_json_option() for object in objects]
|
||||
@classmethod
|
||||
def get_shared_json_attributes(cls, object):
|
||||
return {
|
||||
cls.FLAG_NAME_ATTR_OPTION_TEXT: object.NAME_ATTR_OPTION_TEXT,
|
||||
cls.FLAG_NAME_ATTR_OPTION_VALUE: object.NAME_ATTR_OPTION_VALUE
|
||||
}
|
||||
@@ -61,8 +61,10 @@ class SQLAlchemy_ABC(db.Model, metaclass=SQLAlchemy_ABCMeta):
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
"""
|
||||
def to_json_option(self):
|
||||
pass
|
||||
"""
|
||||
def to_temporary_record(self):
|
||||
pass
|
||||
def to_object_with_missing_attributes(self, excluded_attributes):
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -20,6 +20,8 @@ from typing import ClassVar
|
||||
|
||||
|
||||
class Access_Level(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_ACCESS_LEVEL
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
__tablename__ = 'Shop_Access_Level_Temp'
|
||||
id_access_level = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
@@ -33,8 +35,9 @@ class Access_Level(db.Model, Store_Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
def from_DB_access_level(query_row):
|
||||
access_level = Access_Level()
|
||||
@classmethod
|
||||
def from_DB_access_level(cls, query_row):
|
||||
access_level = cls()
|
||||
access_level.id_access_level = query_row[0]
|
||||
access_level.code = query_row[1]
|
||||
access_level.name = query_row[2]
|
||||
@@ -54,13 +57,14 @@ class Access_Level(db.Model, Store_Base):
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_ACCESS_LEVEL: self.id_access_level[0] if isinstance(self.id_access_level, tuple) else self.id_access_level,
|
||||
self.FLAG_CODE: self.code[0] if isinstance(self.code, tuple) else self.code,
|
||||
self.FLAG_NAME: self.name[0] if isinstance(self.name, tuple) else self.name,
|
||||
self.FLAG_DESCRIPTION: self.description[0] if isinstance(self.description, tuple) else self.description,
|
||||
self.FLAG_PRIORITY: self.priority[0] if isinstance(self.priority, tuple) else self.priority,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_ACTIVE: self.active
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
@@ -79,17 +83,3 @@ class Access_Level(db.Model, Store_Base):
|
||||
access_level.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
access_level.active = json[cls.FLAG_ACTIVE]
|
||||
return access_level
|
||||
|
||||
class Filters_Access_Level(BaseModel):
|
||||
get_inactive_access_level: bool
|
||||
def __init__(self, get_inactive_access_level = False):
|
||||
super().__init__(get_inactive_access_level = get_inactive_access_level)
|
||||
def to_json(self):
|
||||
return {
|
||||
'a_get_inactive_access_level': self.get_inactive_access_level
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
filters = cls()
|
||||
filters.get_inactive_access_level = json['a_get_inactive_access_level']
|
||||
return filters
|
||||
@@ -22,6 +22,7 @@ import lib.argument_validation as av
|
||||
from business_objects.store.product import Product #, Filters_Product
|
||||
from business_objects.store.discount import Discount
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.store.store_base import Store_Base
|
||||
# from forms import Form_Product
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
# from datastores.datastore_store import DataStore_Store # circular
|
||||
@@ -107,7 +108,7 @@ class Basket_Item():
|
||||
subtotal: {self.get_subtotal()}
|
||||
'''
|
||||
|
||||
class Basket():
|
||||
class Basket(Store_Base):
|
||||
KEY_BASKET: str = 'basket'
|
||||
KEY_ID_CURRENCY: str = 'id_currency'
|
||||
KEY_ID_REGION_DELIVERY: str = 'id_region_delivery'
|
||||
@@ -147,6 +148,7 @@ class Basket():
|
||||
return json_list
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
Basket.KEY_ITEMS: self.to_json_list(),
|
||||
Basket.KEY_IS_INCLUDED_VAT: self.is_included_VAT,
|
||||
Basket.KEY_ID_CURRENCY: self.id_currency,
|
||||
|
||||
@@ -11,7 +11,9 @@ Business object for product
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from lib import argument_validation as av
|
||||
# external
|
||||
from typing import ClassVar
|
||||
|
||||
@@ -39,13 +41,10 @@ class Currency_Enum(Enum):
|
||||
# return Resolution_Level_Enum.HIGH
|
||||
"""
|
||||
|
||||
class Currency(db.Model):
|
||||
ATTR_ID_CURRENCY: ClassVar[str] = 'id-currency'
|
||||
FLAG_CODE: ClassVar[str] = 'code-currency'
|
||||
FLAG_NAME: ClassVar[str] = 'name-currency'
|
||||
FLAG_SYMBOL: ClassVar[str] = 'symbol-currency'
|
||||
FLAG_FACTOR_FROM_GBP: ClassVar[str] = 'factor-from-GBP-currency'
|
||||
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display-order-currency'
|
||||
class Currency(db.Model, Store_Base):
|
||||
FLAG_FACTOR_FROM_GBP: ClassVar[str] = 'factor-from-GBP'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_CURRENCY
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
|
||||
id_currency = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
@@ -53,29 +52,35 @@ class Currency(db.Model):
|
||||
symbol = db.Column(db.String(50))
|
||||
factor_from_GBP = db.Column(db.Float)
|
||||
display_order = db.Column(db.Integer)
|
||||
|
||||
def from_DB_currency(query_row):
|
||||
# _m = 'Currency.from_DB_currency'
|
||||
# v_arg_type = 'class attribute'
|
||||
currency = Currency()
|
||||
active = db.Column(db.Boolean)
|
||||
@classmethod
|
||||
def from_DB_currency(cls, query_row):
|
||||
_m = 'Currency.from_DB_currency'
|
||||
v_arg_type = 'class attribute'
|
||||
currency = cls()
|
||||
currency.id_currency = query_row[0]
|
||||
currency.code = query_row[1]
|
||||
currency.name = query_row[2]
|
||||
currency.symbol = query_row[3]
|
||||
currency.factor_from_GBP = query_row[4]
|
||||
currency.display_order = query_row[5]
|
||||
currency.active = av.input_bool(query_row[6], 'active', _m, v_arg_type=v_arg_type)
|
||||
return currency
|
||||
"""
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
_m = 'Currency.from_DB_get_many_product_catalogue'
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue_product_permutation(cls, query_row):
|
||||
_m = 'Currency.from_DB_get_many_product_catalogue_product_permutation'
|
||||
v_arg_type = 'class attribute'
|
||||
currency = Currency()
|
||||
currency.id_permutation = query_row[0]
|
||||
currency.id_product = query_row[1]
|
||||
currency.id_category = query_row[2]
|
||||
currency.id_variation = query_row[3]
|
||||
currency = cls()
|
||||
currency.id_currency = query_row[5]
|
||||
currency.code = query_row[6]
|
||||
currency.symbol = query_row[7]
|
||||
return currency
|
||||
@classmethod
|
||||
def from_DB_get_many_product_price_and_discount_and_delivery_region(cls, query_row):
|
||||
_m = 'Currency.from_DB_get_many_product_price_and_discount_and_delivery_region'
|
||||
v_arg_type = 'class attribute'
|
||||
currency = cls()
|
||||
return currency
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_currency}
|
||||
@@ -84,23 +89,35 @@ class Currency(db.Model):
|
||||
symbol: {self.symbol}
|
||||
factor from GBP: {self.factor_from_GBP}
|
||||
display_order: {self.display_order}
|
||||
active: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
Currency.ATTR_ID_CURRENCY: self.id_currency,
|
||||
Currency.FLAG_CODE: self.code,
|
||||
Currency.FLAG_NAME: self.name,
|
||||
Currency.FLAG_SYMBOL: self.symbol,
|
||||
Currency.FLAG_FACTOR_FROM_GBP: self.factor_from_GBP,
|
||||
Currency.FLAG_DISPLAY_ORDER: self.display_order
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.NAME_ATTR_OPTION_TEXT: self.FLAG_NAME,
|
||||
self.NAME_ATTR_OPTION_VALUE: self.ATTR_ID_CURRENCY,
|
||||
self.ATTR_ID_CURRENCY: self.id_currency,
|
||||
self.FLAG_CODE: self.code,
|
||||
self.FLAG_NAME: self.name,
|
||||
self.FLAG_SYMBOL: self.symbol,
|
||||
self.FLAG_FACTOR_FROM_GBP: self.factor_from_GBP,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
}
|
||||
@staticmethod
|
||||
def from_json(json_currency):
|
||||
currency = Currency()
|
||||
currency.id_currency = json_currency[Currency.ATTR_ID_CURRENCY]
|
||||
currency.code = json_currency[Currency.FLAG_CODE]
|
||||
currency.name = json_currency[Currency.FLAG_NAME]
|
||||
currency.symbol = json_currency[Currency.FLAG_SYMBOL]
|
||||
currency.factor_from_GBP = json_currency[Currency.FLAG_FACTOR_FROM_GBP]
|
||||
currency.display_order = json_currency[Currency.FLAG_DISPLAY_ORDER]
|
||||
return currency
|
||||
@classmethod
|
||||
def from_json(cls, json_currency, key_suffix = ''):
|
||||
currency = cls()
|
||||
currency.id_currency = json_currency[f'{cls.ATTR_ID_CURRENCY}{key_suffix}']
|
||||
currency.code = json_currency.get(f'{cls.FLAG_CODE}{key_suffix}')
|
||||
currency.name = json_currency.get(f'{cls.FLAG_NAME}{key_suffix}')
|
||||
currency.symbol = json_currency.get(f'{cls.FLAG_SYMBOL}{key_suffix}')
|
||||
currency.factor_from_GBP = json_currency.get(f'{cls.FLAG_FACTOR_FROM_GBP}{key_suffix}')
|
||||
currency.display_order = json_currency.get(f'{cls.FLAG_DISPLAY_ORDER}{key_suffix}')
|
||||
currency.active = json_currency.get(f'{cls.FLAG_ACTIVE}{key_suffix}')
|
||||
return currency
|
||||
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_currency,
|
||||
'text': self.name
|
||||
}
|
||||
@@ -11,7 +11,9 @@ Business object for delivery region
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from lib import argument_validation as av
|
||||
# external
|
||||
from enum import Enum
|
||||
from typing import ClassVar
|
||||
@@ -20,12 +22,9 @@ from typing import ClassVar
|
||||
class Enum_Delivery_Region(Enum):
|
||||
UK = 0
|
||||
|
||||
class Delivery_Region(db.Model):
|
||||
ATTR_ID_REGION: ClassVar[str] = 'id-region'
|
||||
FLAG_CODE: ClassVar[str] = 'code-region'
|
||||
FLAG_NAME: ClassVar[str] = 'name-region'
|
||||
FLAG_ACTIVE: ClassVar[str] = 'active-region'
|
||||
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display-order-region'
|
||||
class Delivery_Region(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_DELIVERY_REGION
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
|
||||
id_region = db.Column(db.Integer, primary_key=True)
|
||||
"""
|
||||
@@ -59,19 +58,21 @@ class Delivery_Region(db.Model):
|
||||
self.code = code
|
||||
self.display_order = display_order
|
||||
"""
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
region = Delivery_Region()
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue(cls, query_row):
|
||||
region = cls()
|
||||
region.id_region = query_row[0]
|
||||
region.name = query_row[1]
|
||||
region.code = query_row[2]
|
||||
# self.display_order = query_row[3]
|
||||
return region
|
||||
def from_DB_region(query_row):
|
||||
region = Delivery_Region()
|
||||
@classmethod
|
||||
def from_DB_region(cls, query_row):
|
||||
region = cls()
|
||||
region.id_region = query_row[0]
|
||||
region.code = query_row[1]
|
||||
region.name = query_row[2]
|
||||
region.active = query_row[3]
|
||||
region.active = av.input_bool(query_row[3], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_region')
|
||||
region.display_order = query_row[4]
|
||||
return region
|
||||
def __repr__(self):
|
||||
@@ -84,11 +85,12 @@ class Delivery_Region(db.Model):
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
Delivery_Region.ATTR_ID_REGION: self.id_region,
|
||||
Delivery_Region.FLAG_CODE: self.code,
|
||||
Delivery_Region.FLAG_NAME: self.name,
|
||||
Delivery_Region.FLAG_ACTIVE: self.active,
|
||||
Delivery_Region.FLAG_DISPLAY_ORDER: self.display_order
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_REGION: self.id_region,
|
||||
self.FLAG_CODE: self.code,
|
||||
self.FLAG_NAME: self.name,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order
|
||||
}
|
||||
@staticmethod
|
||||
def from_json(json_region):
|
||||
|
||||
@@ -11,8 +11,9 @@ Business object for product image
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from enum import Enum
|
||||
|
||||
@@ -46,7 +47,7 @@ class Resolution_Level_Enum(Enum):
|
||||
return Resolution_Level_Enum.HIGH
|
||||
|
||||
|
||||
class Image(db.Model):
|
||||
class Image(db.Model, Store_Base):
|
||||
id_image = db.Column(db.Integer, primary_key=True)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
@@ -93,6 +94,15 @@ class Image(db.Model):
|
||||
url: {self.url}
|
||||
display_order: {self.display_order}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PRODUCT_IMAGE: self.id_image,
|
||||
self.ATTR_ID_PRODUCT: self.id_product,
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
|
||||
self.FLAG_URL: self.url,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order
|
||||
}
|
||||
|
||||
|
||||
class Product_Image_Filters():
|
||||
|
||||
@@ -15,6 +15,7 @@ import lib.argument_validation as av
|
||||
# from lib import data_types
|
||||
from business_objects.store.product import Product
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.store.store_base import Store_Base
|
||||
# from forms import Form_Product
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
# external
|
||||
@@ -26,7 +27,7 @@ import locale
|
||||
# VARIABLE INSTANTIATION
|
||||
|
||||
# CLASSES
|
||||
class Order():
|
||||
class Order(Store_Base):
|
||||
category: str
|
||||
product: Product
|
||||
quantity: int
|
||||
@@ -69,6 +70,7 @@ class Order():
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
'product_id': self.product.id_product,
|
||||
'price': self.product.price_GBP_full,
|
||||
'quantity': self.quantity
|
||||
|
||||
@@ -13,7 +13,8 @@ Business object for product
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from lib import data_types
|
||||
from forms.forms import Form_Basket_Add, Form_Basket_Edit, Form_Filters_Permutation
|
||||
from forms.forms import Form_Basket_Add, Form_Basket_Edit
|
||||
from forms.store.product_permutation import Filters_Product_Permutation
|
||||
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.store.discount import Discount
|
||||
@@ -52,14 +53,11 @@ class Enum_Status_Stock(Enum):
|
||||
|
||||
"""
|
||||
class Product(SQLAlchemy_ABC, Store_Base):
|
||||
FLAG_NAME: ClassVar[str] = 'name-product'
|
||||
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display-order-product'
|
||||
FLAG_CAN_VIEW: ClassVar[str] = 'can-view-product'
|
||||
FLAG_CAN_EDIT: ClassVar[str] = 'can-edit-product'
|
||||
FLAG_CAN_ADMIN: ClassVar[str] = 'can-admin-product'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT
|
||||
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME
|
||||
FLAG_HAS_VARIATIONS: ClassVar[str] = 'has-variations-product'
|
||||
FLAG_INDEX_PERMUTATION_SELECTED: ClassVar[str] = 'index-permutation-selected'
|
||||
FLAG_VARIATION_TREES: ClassVar[str] = 'variation-trees'
|
||||
FLAG_PRODUCT_VARIATION_TREES: ClassVar[str] = 'variation-trees'
|
||||
|
||||
id_product = db.Column(db.Integer, primary_key=True)
|
||||
id_category = db.Column(db.Integer)
|
||||
@@ -305,11 +303,12 @@ class Product(SQLAlchemy_ABC, Store_Base):
|
||||
for json_permutation in json[cls.ATTR_ID_PRODUCT_PERMUTATION]:
|
||||
product.permutations.append(Product_Permutation.from_json(json_permutation))
|
||||
product.variation_trees = []
|
||||
for json_tree in json[cls.FLAG_VARIATION_TREES]:
|
||||
for json_tree in json[cls.FLAG_PRODUCT_VARIATION_TREES]:
|
||||
product.variation_trees.append(Product_Variation_Tree.from_json(json_tree))
|
||||
return product
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PRODUCT: self.id_product,
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
|
||||
self.FLAG_NAME: self.name,
|
||||
@@ -320,7 +319,7 @@ class Product(SQLAlchemy_ABC, Store_Base):
|
||||
self.FLAG_HAS_VARIATIONS: self.has_variations,
|
||||
self.FLAG_INDEX_PERMUTATION_SELECTED: self.index_permutation_selected,
|
||||
self.ATTR_ID_PRODUCT_PERMUTATION: [permutation.to_json() for permutation in self.permutations],
|
||||
self.FLAG_VARIATION_TREES: [tree.to_json() for tree in self.variation_trees]
|
||||
self.FLAG_PRODUCT_VARIATION_TREES: [tree.to_json() for tree in self.variation_trees]
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
@@ -421,7 +420,7 @@ class Filters_Product():
|
||||
|
||||
@staticmethod
|
||||
def from_form_filters_product(form):
|
||||
# if not (form is Form_Filters_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Product)
|
||||
has_filter_category = not (form.id_category.data == '0' or form.id_category.data == '')
|
||||
is_not_empty = av.input_bool(form.is_not_empty.data, "is_not_empty", "Filters_Product.from_form_filters_product")
|
||||
@@ -458,8 +457,8 @@ class Filters_Product():
|
||||
)
|
||||
@staticmethod
|
||||
def from_form_filters_product_permutation(form):
|
||||
# if not (form is Form_Filters_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Permutation)
|
||||
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Filters_Product.from_form', Filters_Product_Permutation)
|
||||
has_category_filter = not (form.id_category.data == '0' or form.id_category.data == '')
|
||||
has_product_filter = not (form.id_product.data == '0' or form.id_product.data == '')
|
||||
get_permutations_stock_below_min = av.input_bool(form.is_out_of_stock.data, "is_out_of_stock", "Filters_Product.from_form")
|
||||
@@ -651,7 +650,7 @@ class Filters_Product(Get_Many_Parameters_Base):
|
||||
|
||||
@staticmethod
|
||||
def from_form_filters_product(form):
|
||||
# if not (form is Form_Filters_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Product)
|
||||
has_filter_category = not (form.id_category.data == '0' or form.id_category.data == '')
|
||||
is_not_empty = av.input_bool(form.is_not_empty.data, "is_not_empty", "Filters_Product.from_form_filters_product")
|
||||
@@ -660,7 +659,7 @@ class Filters_Product(Get_Many_Parameters_Base):
|
||||
get_all_product_category = not has_filter_category,
|
||||
get_inactive_product_category = not active,
|
||||
# get_first_product_category_only = False,
|
||||
ids_product_category = form.id_category.data,
|
||||
ids_product_category = str(form.id_category.data),
|
||||
get_all_product = True,
|
||||
get_inactive_product = not active,
|
||||
# get_first_product_only = False,
|
||||
@@ -686,23 +685,23 @@ class Filters_Product(Get_Many_Parameters_Base):
|
||||
# ids_discount = '',
|
||||
get_products_quantity_stock_below_min = False
|
||||
)
|
||||
@staticmethod
|
||||
@staticmethod
|
||||
def from_form_filters_product_permutation(form):
|
||||
# if not (form is Form_Filters_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Permutation)
|
||||
has_category_filter = not (form.id_category.data == '0' or form.id_category.data == '')
|
||||
has_product_filter = not (form.id_product.data == '0' or form.id_product.data == '')
|
||||
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Filters_Product.from_form', Filters_Product_Permutation)
|
||||
has_category_filter = not (form.id_category.data is None or form.id_category.data == '0' or form.id_category.data == '')
|
||||
has_product_filter = not (form.id_product.data is None or form.id_product.data == '0' or form.id_product.data == '')
|
||||
get_permutations_stock_below_min = av.input_bool(form.is_out_of_stock.data, "is_out_of_stock", "Filters_Product.from_form")
|
||||
print(f'form question: {type(form.is_out_of_stock)}\nbool interpretted: {get_permutations_stock_below_min}\type form: {type(form)}')
|
||||
return Filters_Product(
|
||||
get_all_product_category = not has_category_filter,
|
||||
get_inactive_product_category = False,
|
||||
# get_first_product_category_only = False,
|
||||
ids_product_category = form.id_category.data,
|
||||
ids_product_category = str(form.id_category.data) if has_category_filter else '',
|
||||
get_all_product = not has_product_filter,
|
||||
get_inactive_product = False,
|
||||
# get_first_product_only = False,
|
||||
ids_product = form.id_product.data,
|
||||
ids_product = str(form.id_product.data) if has_product_filter else '',
|
||||
get_all_permutation = not get_permutations_stock_below_min,
|
||||
get_inactive_permutation = False,
|
||||
# get_first_permutation_only = False,
|
||||
|
||||
@@ -28,6 +28,9 @@ from typing import ClassVar
|
||||
|
||||
class Product_Category(SQLAlchemy_ABC, Store_Base):
|
||||
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = 'id_access_level_required'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_CATEGORY
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
|
||||
__tablename__ = 'Shop_Product_Category_Temp'
|
||||
id_category = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
@@ -48,8 +51,9 @@ class Product_Category(SQLAlchemy_ABC, Store_Base):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.name_access_level_required = None
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
category = Product_Category()
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue(cls, query_row):
|
||||
category = cls()
|
||||
category.id_category = query_row[0]
|
||||
category.code = query_row[1]
|
||||
category.name = query_row[2]
|
||||
@@ -57,10 +61,10 @@ class Product_Category(SQLAlchemy_ABC, Store_Base):
|
||||
category.id_access_level_required = query_row[4]
|
||||
category.name_access_level_required = query_row[5]
|
||||
category.display_order = query_row[6]
|
||||
category.active = query_row[7]
|
||||
category.can_view = query_row[8]
|
||||
category.can_edit = query_row[9]
|
||||
category.can_admin = query_row[10]
|
||||
category.active = av.input_bool(query_row[7], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_get_many_product_catalogue')
|
||||
category.can_view = av.input_bool(query_row[8], cls.FLAG_CAN_VIEW, f'{cls.__name__}.from_DB_get_many_product_catalogue')
|
||||
category.can_edit = av.input_bool(query_row[9], cls.FLAG_CAN_EDIT, f'{cls.__name__}.from_DB_get_many_product_catalogue')
|
||||
category.can_admin = av.input_bool(query_row[10], cls.FLAG_CAN_ADMIN, f'{cls.__name__}.from_DB_get_many_product_catalogue')
|
||||
return category
|
||||
"""
|
||||
def key_product_index_from_ids_product_permutation(id_product, id_permutation):
|
||||
@@ -178,7 +182,7 @@ class Product_Category(SQLAlchemy_ABC, Store_Base):
|
||||
return list_products
|
||||
def to_json(self):
|
||||
return {
|
||||
self.FLAG_KEY_PRIMARY: self.ATTR_ID_PRODUCT_CATEGORY,
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category[0] if isinstance(self.id_category, tuple) else self.id_category,
|
||||
self.FLAG_CODE: self.code[0] if isinstance(self.code, tuple) else self.code,
|
||||
self.FLAG_NAME: self.name[0] if isinstance(self.name, tuple) else self.name,
|
||||
@@ -195,12 +199,12 @@ class Product_Category(SQLAlchemy_ABC, Store_Base):
|
||||
def from_json(cls, json):
|
||||
print(f' Category.from_json: {json}')
|
||||
category = cls()
|
||||
category.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY],
|
||||
category.code = json[cls.FLAG_CODE],
|
||||
category.name = json[cls.FLAG_NAME],
|
||||
category.description = json[cls.FLAG_DESCRIPTION],
|
||||
category.id_access_level_required = json[cls.ATTR_ID_ACCESS_LEVEL],
|
||||
category.name_access_level_required = json.get(cls.FLAG_ACCESS_LEVEL_REQUIRED, ''),
|
||||
category.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
category.code = json[cls.FLAG_CODE]
|
||||
category.name = json[cls.FLAG_NAME]
|
||||
category.description = json[cls.FLAG_DESCRIPTION]
|
||||
category.id_access_level_required = json[cls.ATTR_ID_ACCESS_LEVEL]
|
||||
category.name_access_level_required = json.get(cls.FLAG_ACCESS_LEVEL_REQUIRED, '')
|
||||
category.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
category.active = json[cls.FLAG_ACTIVE]
|
||||
category.can_view = json.get(cls.FLAG_CAN_VIEW, False)
|
||||
@@ -258,8 +262,9 @@ class Filters_Product_Category(BaseModel, Store_Base):
|
||||
ids_product_category = '',
|
||||
ids_product = ''
|
||||
)
|
||||
def to_json(self):
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
'a_ids_product_category': self.ids_product_category,
|
||||
'a_ids_product': self.ids_product
|
||||
}
|
||||
@@ -282,10 +287,11 @@ class Filters_Product_Category(Get_Many_Parameters_Base):
|
||||
is_not_empty = False,
|
||||
active = True
|
||||
)
|
||||
def to_json(self):
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.FLAG_IS_NOT_EMPTY: self.is_not_empty,
|
||||
self.FLAG_ACTIVE: self.active
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
@@ -379,13 +385,19 @@ class Product_Category_Container(Store_Base):
|
||||
for category in self.categories:
|
||||
list_categories.append({'value': category.id_category, 'text': category.name})
|
||||
return list_categories
|
||||
def to_product_option_list(self):
|
||||
def get_list_products(self):
|
||||
list_products = []
|
||||
for category in self.categories:
|
||||
# list_products.append(category.to_product_option_list())
|
||||
"""
|
||||
for product in category.products:
|
||||
list_products.append({'value': product.id_product, 'text': product.name, Product.ATTR_ID_PRODUCT_CATEGORY: product.id_category})
|
||||
"""
|
||||
list_products += category.products
|
||||
return list_products
|
||||
def to_product_option_list(self):
|
||||
list_products = self.get_list_products()
|
||||
return [{'value': product.id_product, 'text': product.name, Product.ATTR_ID_PRODUCT_CATEGORY: product.id_category} for product in list_products]
|
||||
def get_product_option_lists_by_category(self):
|
||||
dict_lists_products = {}
|
||||
for category in self.categories:
|
||||
@@ -393,6 +405,7 @@ class Product_Category_Container(Store_Base):
|
||||
return dict_lists_products
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
f'{self.FLAG_ROWS}': [category.to_json() for category in self.categories]
|
||||
}
|
||||
"""
|
||||
@@ -412,4 +425,64 @@ class Product_Category_Container(Store_Base):
|
||||
for column in self.__table__.columns
|
||||
if column.name not in ['created_on', 'created_by']
|
||||
}
|
||||
return self.to_object_with_missing_attributes(excluded_attributes)
|
||||
return self.to_object_with_missing_attributes(excluded_attributes)
|
||||
|
||||
|
||||
"""
|
||||
class Table_Shop_Product_Category(db.Model):
|
||||
__tablename__ = 'Shop_Product_Category'
|
||||
id_category: int = db.Column(db.Integer, primary_key=True)
|
||||
code: str = db.Column(db.String(50))
|
||||
name: str = db.Column(db.String(255))
|
||||
description: str = db.Column(db.String(4000))
|
||||
active: bool = db.Column(db.Boolean)
|
||||
display_order: int = db.Column(db.Integer)
|
||||
created_on: datetime = db.Column(db.DateTime)
|
||||
created_by: int = db.Column(db.Integer)
|
||||
id_change_set: int = db.Column(db.Integer)
|
||||
"""
|
||||
class Product_Category_Temp(db.Model):
|
||||
__tablename__ = 'Shop_Product_Category_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_category: int = db.Column(db.Integer, primary_key=True)
|
||||
code: str = db.Column(db.String(50))
|
||||
name: str = db.Column(db.String(255))
|
||||
description: str = db.Column(db.String(4000))
|
||||
id_access_level_required: int = db.Column(db.Integer)
|
||||
active: bool = db.Column(db.Boolean)
|
||||
display_order: int = db.Column(db.Integer)
|
||||
guid: str = db.Column(db.BINARY(36))
|
||||
# created_on: datetime = db.Column(db.DateTime)
|
||||
# created_by: int = db.Column(db.Integer)
|
||||
|
||||
@classmethod
|
||||
def from_product_category(cls, product_category):
|
||||
row = cls()
|
||||
row.id_category = product_category.id_category[0] if isinstance(product_category.id_category, tuple) else product_category.id_category
|
||||
row.code = product_category.code[0] if isinstance(product_category.code, tuple) else product_category.code
|
||||
row.name = product_category.name[0] if isinstance(product_category.name, tuple) else product_category.name
|
||||
row.description = product_category.description[0] if isinstance(product_category.description, tuple) else product_category.description
|
||||
row.id_access_level_required = product_category.id_access_level_required[0] if isinstance(product_category.id_access_level_required, tuple) else product_category.id_access_level_required
|
||||
row.active = product_category.active
|
||||
row.display_order = product_category.display_order
|
||||
"""
|
||||
row.guid = product_category.guid
|
||||
row.created_on = product_category.created_on
|
||||
row.created_by = product_category.created_by
|
||||
"""
|
||||
return row
|
||||
def to_json(self):
|
||||
return {
|
||||
'id_category': self.id_category,
|
||||
'code': self.code,
|
||||
'name': self.name,
|
||||
'description': self.description,
|
||||
'id_access_level_required': self.id_access_level_required,
|
||||
'active': av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
'display_order': self.display_order,
|
||||
'guid': self.guid,
|
||||
}
|
||||
"""
|
||||
'created_on': self.created_on,
|
||||
'created_by': self.created_by
|
||||
"""
|
||||
|
||||
@@ -13,7 +13,8 @@ Business object for product permutation
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from lib import data_types
|
||||
from forms.forms import Form_Basket_Add, Form_Basket_Edit, Form_Filters_Permutation
|
||||
from forms.forms import Form_Basket_Add, Form_Basket_Edit
|
||||
from business_objects.store.currency import Currency
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.store.discount import Discount
|
||||
from business_objects.store.image import Image
|
||||
@@ -22,42 +23,91 @@ from business_objects.store.stock_item import Stock_Item
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from business_objects.store.product_variation import Product_Variation
|
||||
from business_objects.store.product_variation_tree import Product_Variation_Tree
|
||||
from business_objects.unit_measurement import Unit_Measurement
|
||||
from extensions import db
|
||||
# external
|
||||
from datetime import datetime, timedelta
|
||||
import locale
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
class Product_Permutation(db.Model, Store_Base):
|
||||
FLAG_QUANTITY_STOCK = 'quantity-stock'
|
||||
FLAG_QUANTITY_MIN = 'quantity-min'
|
||||
FLAG_QUANTITY_MAX = 'quantity-max'
|
||||
FLAG_COST_LOCAL = 'cost-local'
|
||||
NAME_ATTR_OPTION_VALUE = Store_Base.ATTR_ID_PRODUCT_PERMUTATION
|
||||
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME
|
||||
FLAG_CURRENCY_COST = f'{Currency.ATTR_ID_CURRENCY}_cost'
|
||||
FLAG_CODE_CURRENCY_COST = f'{Currency.FLAG_CODE}_cost'
|
||||
FLAG_SYMBOL_CURRENCY_COST = f'{Currency.FLAG_SYMBOL}_cost'
|
||||
FLAG_COST_LOCAL = 'cost_local'
|
||||
FLAG_PROFIT_LOCAL_MIN = 'profit_local_min'
|
||||
FLAG_HAS_VARIATIONS = 'has_variations'
|
||||
FLAG_LATENCY_MANUFACTURE_DAYS = 'latency_manufacture_days'
|
||||
FLAG_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.ATTR_ID_UNIT_MEASUREMENT}_quantity'
|
||||
FLAG_SYMBOL_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.FLAG_SYMBOL}_quantity'
|
||||
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX}_quantity'
|
||||
FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.FLAG_NAME_SINGULAR}_quantity'
|
||||
FLAG_NAME_PLURAL_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.FLAG_NAME_PLURAL}_quantity'
|
||||
FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP = 'count_unit_measurement_per_quantity_step'
|
||||
FLAG_QUANTITY_STOCK = 'quantity_stock'
|
||||
FLAG_IS_SUBSCRIPTION = 'is_subscription'
|
||||
FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.ATTR_ID_UNIT_MEASUREMENT}_interval_recurrence'
|
||||
FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.FLAG_SYMBOL}_unit_measurement_interval_recurrence'
|
||||
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX}_unit_measurement_interval_recurrence'
|
||||
FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.FLAG_NAME_SINGULAR}_unit_measurement_interval_recurrence'
|
||||
FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.FLAG_NAME_PLURAL}_unit_measurement_interval_recurrence'
|
||||
FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = 'count_interval_recurrence'
|
||||
FLAG_ID_STRIPE_PRODUCT = 'id_stripe_product'
|
||||
FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED = 'does_expire_faster_once_unsealed'
|
||||
FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.ATTR_ID_UNIT_MEASUREMENT}_interval_expiration_unsealed'
|
||||
FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.FLAG_SYMBOL}_interval_expiration_unsealed'
|
||||
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX}_interval_expiration_unsealed'
|
||||
FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.FLAG_NAME_SINGULAR}_interval_expiration_unsealed'
|
||||
FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.FLAG_NAME_PLURAL}_interval_expiration_unsealed'
|
||||
FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = 'count_interval_expiration_unsealed'
|
||||
|
||||
id_product = db.Column(db.Integer, primary_key=True)
|
||||
id_permutation = db.Column(db.Integer, primary_key=True)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
# name = db.Column(db.String(255))
|
||||
description = db.Column(db.String(4000))
|
||||
# price_GBP_full = db.Column(db.Float)
|
||||
# price_GBP_min = db.Column(db.Float)
|
||||
"""
|
||||
id_currency_cost = db.Column(db.Integer)
|
||||
code_currency_cost = db.Column(db.String(3))
|
||||
symbol_currency_cost = db.Column(db.String(3))
|
||||
"""
|
||||
# currency_cost: Currency
|
||||
cost_local = db.Column(db.Float)
|
||||
profit_local_min = db.Column(db.Float)
|
||||
has_variations = db.Column(db.Boolean)
|
||||
id_category = db.Column(db.Integer)
|
||||
latency_manufacture = db.Column(db.Integer)
|
||||
latency_manufacture_days = db.Column(db.Integer)
|
||||
id_unit_measurement_quantity = db.Column(db.Integer)
|
||||
symbol_unit_measurement_quantity = db.Column(db.String(50))
|
||||
symbol_is_suffix_not_prefix_unit_measurement_quantity = db.Column(db.Boolean)
|
||||
name_singular_unit_measurement_quantity = db.Column(db.String(255))
|
||||
name_plural_unit_measurement_quantity = db.Column(db.String(256))
|
||||
count_unit_measurement_per_quantity_step = db.Column(db.Integer)
|
||||
quantity_min = db.Column(db.Float)
|
||||
quantity_max = db.Column(db.Float)
|
||||
quantity_step = db.Column(db.Float)
|
||||
quantity_stock = db.Column(db.Float)
|
||||
id_stripe_product = db.Column(db.String(100))
|
||||
is_subscription = db.Column(db.Boolean)
|
||||
name_recurrence_interval = db.Column(db.String(255))
|
||||
name_plural_recurrence_interval = db.Column(db.String(256))
|
||||
count_recurrence_interval = db.Column(db.Integer)
|
||||
id_unit_measurement_interval_recurrence = db.Column(db.Integer)
|
||||
symbol_unit_measurement_interval_recurrence = db.Column(db.String(50))
|
||||
symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence = db.Column(db.Boolean)
|
||||
name_singular_unit_measurement_interval_recurrence = db.Column(db.String(255))
|
||||
name_plural_unit_measurement_interval_recurrence = db.Column(db.String(256))
|
||||
count_interval_recurrence = db.Column(db.Integer)
|
||||
id_stripe_product = db.Column(db.String(100))
|
||||
does_expire_faster_once_unsealed = db.Column(db.Boolean)
|
||||
id_unit_measurement_interval_expiration_unsealed = db.Column(db.Integer)
|
||||
symbol_unit_measurement_interval_expiration_unsealed = db.Column(db.String(50))
|
||||
symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed = db.Column(db.Boolean)
|
||||
name_singular_unit_measurement_interval_expiration_unsealed = db.Column(db.String(255))
|
||||
name_plural_unit_measurement_interval_expiration_unsealed = db.Column(db.String(256))
|
||||
count_interval_expiration_unsealed = db.Column(db.Integer)
|
||||
has_variations = db.Column(db.Boolean)
|
||||
active = db.Column(db.Boolean)
|
||||
display_order = db.Column(db.Integer)
|
||||
# display_order = db.Column(db.Integer)
|
||||
can_view = db.Column(db.Boolean)
|
||||
can_edit = db.Column(db.Boolean)
|
||||
can_admin = db.Column(db.Boolean)
|
||||
@@ -82,41 +132,56 @@ class Product_Permutation(db.Model, Store_Base):
|
||||
self.stock_item_index = {}
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.currency_cost = None
|
||||
self.form_basket_add = Form_Basket_Add()
|
||||
self.form_basket_edit = Form_Basket_Edit()
|
||||
self.is_unavailable_in_currency_or_region = False
|
||||
# self.is_available = False
|
||||
self.variation_tree = None
|
||||
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
_m = 'Product_Permutation.from_DB_get_many_product_catalogue'
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue(cls, query_row):
|
||||
_m = f'{cls.__name__}.from_DB_get_many_product_catalogue'
|
||||
v_arg_type = 'class attribute'
|
||||
print(f'query_row: {query_row}')
|
||||
permutation = Product_Permutation()
|
||||
permutation = cls()
|
||||
permutation.id_permutation = query_row[0]
|
||||
permutation.id_product = query_row[1]
|
||||
permutation.id_category = query_row[2]
|
||||
permutation.description = query_row[3]
|
||||
permutation.cost_local = query_row[4]
|
||||
permutation.id_currency_cost = query_row[5]
|
||||
permutation.code_currency_cost = query_row[6]
|
||||
permutation.symbol_currency_cost = query_row[7]
|
||||
# permutation.profit_local_min = query_row[8]
|
||||
permutation.latency_manufacture = query_row[9]
|
||||
permutation.quantity_min = query_row[10]
|
||||
permutation.quantity_max = query_row[11]
|
||||
permutation.quantity_step = query_row[12]
|
||||
permutation.quantity_stock = query_row[13]
|
||||
permutation.id_stripe_product = query_row[14]
|
||||
permutation.is_subscription = av.input_bool(query_row[15], "is_subscription", _m, v_arg_type=v_arg_type)
|
||||
permutation.name_recurrence_interval = query_row[16]
|
||||
permutation.name_plural_recurrence_interval = query_row[17]
|
||||
permutation.count_recurrence_interval = query_row[18]
|
||||
permutation.active = query_row[19]
|
||||
permutation.display_order = query_row[20]
|
||||
permutation.can_view = av.input_bool(query_row[21], "can_view", _m, v_arg_type=v_arg_type)
|
||||
permutation.can_edit = av.input_bool(query_row[22], "can_edit", _m, v_arg_type=v_arg_type)
|
||||
permutation.can_admin = av.input_bool(query_row[23], "can_admin", _m, v_arg_type=v_arg_type)
|
||||
permutation.currency_cost = Currency.from_DB_get_many_product_catalogue_product_permutation(query_row)
|
||||
permutation.profit_local_min = query_row[8]
|
||||
permutation.latency_manufacture_days = query_row[9]
|
||||
permutation.id_unit_measurement_quantity = query_row[10]
|
||||
permutation.symbol_unit_measurement_quantity = query_row[11]
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_quantity = av.input_bool(query_row[12], cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_QUANTITY, _m, v_arg_type=v_arg_type)
|
||||
permutation.name_singular_unit_measurement_quantity = query_row[13]
|
||||
permutation.name_plural_unit_measurement_quantity = query_row[14]
|
||||
permutation.count_unit_measurement_per_quantity_step = query_row[15]
|
||||
permutation.quantity_min = query_row[16]
|
||||
permutation.quantity_max = query_row[17]
|
||||
permutation.quantity_stock = query_row[18]
|
||||
permutation.is_subscription = av.input_bool(query_row[19], "is_subscription", _m, v_arg_type=v_arg_type)
|
||||
permutation.id_unit_measurement_interval_recurrence = query_row[20]
|
||||
permutation.symbol_unit_measurement_interval_recurrence = query_row[21]
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence = av.input_bool(query_row[22], cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_RECURRENCE, _m, v_arg_type=v_arg_type)
|
||||
permutation.name_singular_unit_measurement_interval_recurrence = query_row[23]
|
||||
permutation.name_plural_unit_measurement_interval_recurrence = query_row[24]
|
||||
permutation.count_interval_recurrence = query_row[25]
|
||||
permutation.id_stripe_product = query_row[26]
|
||||
permutation.does_expire_faster_once_unsealed = av.input_bool(query_row[27], "does_expire_faster_once_unsealed", _m, v_arg_type=v_arg_type)
|
||||
permutation.id_unit_measurement_interval_expiration_unsealed = query_row[28]
|
||||
permutation.symbol_unit_measurement_interval_expiration_unsealed = query_row[29]
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed = av.input_bool(query_row[30], cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED, _m, v_arg_type=v_arg_type)
|
||||
permutation.name_singular_unit_measurement_interval_expiration_unsealed = query_row[31]
|
||||
permutation.name_plural_unit_measurement_interval_expiration_unsealed = query_row[32]
|
||||
permutation.count_interval_expiration_unsealed = query_row[33]
|
||||
permutation.has_variations = av.input_bool(query_row[34], cls.FLAG_HAS_VARIATIONS, _m, v_arg_type=v_arg_type)
|
||||
permutation.active = av.input_bool(query_row[35], cls.FLAG_ACTIVE, _m, v_arg_type=v_arg_type)
|
||||
# permutation.display_order = query_row[27]
|
||||
permutation.can_view = av.input_bool(query_row[36], "can_view", _m, v_arg_type=v_arg_type)
|
||||
permutation.can_edit = av.input_bool(query_row[37], "can_edit", _m, v_arg_type=v_arg_type)
|
||||
permutation.can_admin = av.input_bool(query_row[38], "can_admin", _m, v_arg_type=v_arg_type)
|
||||
return permutation
|
||||
|
||||
def from_DB_Stripe_product(query_row):
|
||||
@@ -136,8 +201,8 @@ class Product_Permutation(db.Model, Store_Base):
|
||||
# permutation.price_GBP_full = query_row[1]
|
||||
permutation.id_stripe_product = query_row[2]
|
||||
permutation.is_subscription = av.input_bool(query_row[3], "is_subscription", _m, v_arg_type=v_arg_type)
|
||||
permutation.name_recurrence_interval = query_row[4]
|
||||
permutation.count_recurrence_interval = query_row[5]
|
||||
permutation.name_singular_unit_measurement_interval_recurrence = query_row[4]
|
||||
permutation.count_interval_recurrence = query_row[5]
|
||||
return permutation
|
||||
"""
|
||||
def from_json(json_basket_item, key_id_product, key_id_permutation):
|
||||
@@ -150,49 +215,102 @@ class Product_Permutation(db.Model, Store_Base):
|
||||
"""
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = f'{cls.__name__}.from_json'
|
||||
permutation = cls()
|
||||
permutation.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
permutation.id_product = json[cls.ATTR_ID_PRODUCT]
|
||||
permutation.id_permutation = json[cls.ATTR_ID_PRODUCT_PERMUTATION]
|
||||
permutation.has_variations = len(json[cls.ATTR_ID_PRODUCT_VARIATION]) > 0
|
||||
if permutation.has_variations:
|
||||
for jsonProductVariation in json[cls.ATTR_ID_PRODUCT_VARIATION]:
|
||||
variation = Product_Variation.from_json(jsonProductVariation)
|
||||
permutation.add_product_variation(variation)
|
||||
permutation.quantity_stock = json[cls.FLAG_QUANTITY_STOCK]
|
||||
permutation.id_product = json[cls.ATTR_ID_PRODUCT]
|
||||
permutation.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
permutation.description = json[cls.FLAG_DESCRIPTION]
|
||||
permutation.cost_local = json[cls.FLAG_COST_LOCAL]
|
||||
permutation.currency_cost = Currency.from_json(json, '_cost')
|
||||
permutation.profit_local_min = json[cls.FLAG_PROFIT_LOCAL_MIN]
|
||||
permutation.latency_manufacture_days = json[cls.FLAG_LATENCY_MANUFACTURE_DAYS]
|
||||
permutation.id_unit_measurement_quantity = json[cls.FLAG_UNIT_MEASUREMENT_QUANTITY]
|
||||
permutation.symbol_unit_measurement_quantity = json.get(cls.FLAG_SYMBOL_UNIT_MEASUREMENT_QUANTITY)
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_quantity = json.get(cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_QUANTITY)
|
||||
permutation.name_singular_unit_measurement_quantity = json.get(cls.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_QUANTITY)
|
||||
permutation.name_plural_unit_measurement_quantity = json.get(cls.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_QUANTITY)
|
||||
permutation.count_unit_measurement_per_quantity_step = json[cls.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP]
|
||||
permutation.quantity_min = json[cls.FLAG_QUANTITY_MIN]
|
||||
permutation.quantity_max = json[cls.FLAG_QUANTITY_MAX]
|
||||
permutation.quantity_stock = json[cls.FLAG_QUANTITY_STOCK]
|
||||
permutation.is_subscription = 1 if av.input_bool(json[cls.FLAG_IS_SUBSCRIPTION], cls.FLAG_IS_SUBSCRIPTION, _m) else 0
|
||||
permutation.id_unit_measurement_interval_recurrence = json[cls.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE] if json[cls.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE] != '' else None
|
||||
permutation.symbol_unit_measurement_interval_recurrence = json.get(cls.FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE)
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence = json.get(cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_RECURRENCE)
|
||||
permutation.name_singular_unit_measurement_interval_recurrence = json.get(cls.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_RECURRENCE)
|
||||
permutation.name_plural_unit_measurement_interval_recurrence = json.get(cls.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE)
|
||||
permutation.count_interval_recurrence = json[cls.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE] if json[cls.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE] != '' else None
|
||||
permutation.id_stripe_product = json[cls.FLAG_ID_STRIPE_PRODUCT]
|
||||
permutation.does_expire_faster_once_unsealed = 1 if av.input_bool(json[cls.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED], cls.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED, _m) else 0
|
||||
permutation.id_unit_measurement_interval_expiration_unsealed = json[cls.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED] if json[cls.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED] != '' else None
|
||||
permutation.symbol_unit_measurement_interval_expiration_unsealed = json.get(cls.FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED)
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed = json.get(cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED)
|
||||
permutation.name_singular_unit_measurement_interval_expiration_unsealed = json.get(cls.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED)
|
||||
permutation.name_plural_unit_measurement_interval_expiration_unsealed = json.get(cls.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED)
|
||||
permutation.count_interval_expiration_unsealed = json[cls.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED] if json[cls.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED] != '' else None
|
||||
permutation.has_variations = json[cls.FLAG_HAS_VARIATIONS]
|
||||
permutation.active = 1 if av.input_bool(json[cls.FLAG_ACTIVE], cls.FLAG_ACTIVE, _m) else 0
|
||||
if permutation.has_variations:
|
||||
permutation.variation_tree = Product_Variation_Tree.from_json_str(json[cls.FLAG_PRODUCT_VARIATIONS])
|
||||
"""
|
||||
for jsonProductVariation in json[cls.FLAG_PRODUCT_VARIATIONS]:
|
||||
variation = Product_Variation.from_json(jsonProductVariation)
|
||||
permutation.add_product_variation(variation)
|
||||
"""
|
||||
return permutation
|
||||
def to_json(self):
|
||||
return {
|
||||
'id_product': {self.id_product},
|
||||
'id_permutation': {self.id_permutation},
|
||||
'description': {self.description},
|
||||
'id_category': {self.id_category},
|
||||
'latency_manufacture': {self.latency_manufacture},
|
||||
'quantity_min': {self.quantity_min},
|
||||
'quantity_max': {self.quantity_max},
|
||||
'quantity_step': {self.quantity_step},
|
||||
'quantity_stock': {self.quantity_stock},
|
||||
'id_stripe_product': {self.id_stripe_product},
|
||||
'is_subscription': {self.is_subscription},
|
||||
'name_recurrence_interval': {self.name_recurrence_interval},
|
||||
'name_plural_recurrence_interval': {self.name_plural_recurrence_interval},
|
||||
'count_recurrence_interval': {self.count_recurrence_interval},
|
||||
'display_order': {self.display_order},
|
||||
'can_view': {self.can_view},
|
||||
'can_edit': {self.can_edit},
|
||||
'can_admin': {self.can_admin},
|
||||
'variations': {self.variations},
|
||||
'images': {self.images},
|
||||
'delivery_options': {self.delivery_options},
|
||||
'prices': {self.prices}
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PRODUCT_PERMUTATION: self.id_permutation,
|
||||
self.ATTR_ID_PRODUCT: self.id_product,
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
|
||||
self.FLAG_DESCRIPTION: self.description,
|
||||
self.FLAG_COST_LOCAL: self.cost_local,
|
||||
self.FLAG_CURRENCY_COST: self.currency_cost.to_json(),
|
||||
self.FLAG_PROFIT_LOCAL_MIN: self.profit_local_min,
|
||||
self.FLAG_LATENCY_MANUFACTURE_DAYS: self.latency_manufacture_days,
|
||||
self.FLAG_UNIT_MEASUREMENT_QUANTITY: self.id_unit_measurement_quantity,
|
||||
self.FLAG_SYMBOL_UNIT_MEASUREMENT_QUANTITY: self.symbol_unit_measurement_quantity,
|
||||
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_QUANTITY: self.symbol_is_suffix_not_prefix_unit_measurement_quantity,
|
||||
self.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_QUANTITY: self.name_singular_unit_measurement_quantity,
|
||||
self.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_QUANTITY: self.name_plural_unit_measurement_quantity,
|
||||
self.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP: self.count_unit_measurement_per_quantity_step,
|
||||
self.FLAG_QUANTITY_MIN: self.quantity_min,
|
||||
self.FLAG_QUANTITY_MAX: self.quantity_max,
|
||||
self.FLAG_QUANTITY_STOCK: self.quantity_stock,
|
||||
self.FLAG_IS_SUBSCRIPTION: self.is_subscription,
|
||||
self.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.id_unit_measurement_interval_recurrence,
|
||||
self.FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.symbol_unit_measurement_interval_recurrence,
|
||||
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence,
|
||||
self.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.name_singular_unit_measurement_interval_recurrence,
|
||||
self.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.name_plural_unit_measurement_interval_recurrence,
|
||||
self.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.count_interval_recurrence,
|
||||
self.FLAG_ID_STRIPE_PRODUCT: self.id_stripe_product,
|
||||
self.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED: self.does_expire_faster_once_unsealed,
|
||||
self.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.id_unit_measurement_interval_expiration_unsealed,
|
||||
self.FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.symbol_unit_measurement_interval_expiration_unsealed,
|
||||
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed,
|
||||
self.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.name_singular_unit_measurement_interval_expiration_unsealed,
|
||||
self.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.name_plural_unit_measurement_interval_expiration_unsealed,
|
||||
self.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.count_interval_expiration_unsealed,
|
||||
self.FLAG_HAS_VARIATIONS: self.has_variations,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
self.FLAG_CAN_VIEW: self.can_view,
|
||||
self.FLAG_CAN_EDIT: self.can_edit,
|
||||
self.FLAG_CAN_ADMIN: self.can_admin,
|
||||
self.FLAG_PRODUCT_VARIATION: [variation.to_json() for variation in self.variations],
|
||||
self.FLAG_PRODUCT_IMAGE: [image.to_json() for image in self.images],
|
||||
self.FLAG_DELIVERY_OPTION: [option.to_json() for option in self.delivery_options],
|
||||
self.FLAG_PRODUCT_PRICE: [price.to_json() for price in self.prices],
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_permutation,
|
||||
'text': self.get_name_variations()
|
||||
}
|
||||
def get_name(self):
|
||||
return
|
||||
def get_name_variations(self):
|
||||
return self.variation_tree.get_name_variations()
|
||||
def is_available(self):
|
||||
@@ -207,10 +325,10 @@ class Product_Permutation(db.Model, Store_Base):
|
||||
return price.value_local_VAT_excl
|
||||
|
||||
def output_lead_time(self):
|
||||
return '1 day' if self.latency_manufacture == 1 else f'{self.latency_manufacture} days'
|
||||
return '1 day' if self.latency_manufacture_days == 1 else f'{self.latency_manufacture_days} days'
|
||||
|
||||
def output_delivery_date(self):
|
||||
return (datetime.now() + timedelta(days=self.latency_manufacture)).strftime('%A, %d %B %Y')
|
||||
return (datetime.now() + timedelta(days=self.latency_manufacture_days)).strftime('%A, %d %B %Y')
|
||||
|
||||
def output_price(self, is_included_VAT):
|
||||
if self.is_unavailable_in_currency_or_region:
|
||||
@@ -252,21 +370,38 @@ class Product_Permutation(db.Model, Store_Base):
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''Product_Permutation
|
||||
id_product: {self.id_product}
|
||||
id_permutation: {self.id_permutation}
|
||||
description: {self.description}
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
latency_manufacture: {self.latency_manufacture}
|
||||
description: {self.description}
|
||||
cost_local: {self.cost_local}
|
||||
currency_cost: {self.currency_cost}
|
||||
latency_manufacture_days: {self.latency_manufacture_days}
|
||||
id_unit_measurement_quantity: {self.id_unit_measurement_quantity}
|
||||
symbol_unit_measurement_quantity: {self.symbol_unit_measurement_quantity}
|
||||
symbol_is_suffix_not_prefix_unit_measurement_quantity: {self.symbol_is_suffix_not_prefix_unit_measurement_quantity}
|
||||
name_singular_unit_measurement_quantity: {self.name_singular_unit_measurement_quantity}
|
||||
name_plural_unit_measurement_quantity: {self.name_plural_unit_measurement_quantity}
|
||||
count_unit_measurement_per_quantity_step: {self.count_unit_measurement_per_quantity_step}
|
||||
quantity_min: {self.quantity_min}
|
||||
quantity_max: {self.quantity_max}
|
||||
quantity_step: {self.quantity_step}
|
||||
quantity_stock: {self.quantity_stock}
|
||||
id_stripe_product: {self.id_stripe_product}
|
||||
is_subscription: {self.is_subscription}
|
||||
name_recurrence_interval: {self.name_recurrence_interval}
|
||||
name_plural_recurrence_interval: {self.name_plural_recurrence_interval}
|
||||
count_recurrence_interval: {self.count_recurrence_interval}
|
||||
display_order: {self.display_order}
|
||||
id_unit_measurement_interval_recurrence: {self.id_unit_measurement_interval_recurrence}
|
||||
symbol_unit_measurement_interval_recurrence: {self.symbol_unit_measurement_interval_recurrence}
|
||||
symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence: {self.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence}
|
||||
name_singular_unit_measurement_interval_recurrence: {self.name_singular_unit_measurement_interval_recurrence}
|
||||
name_plural_unit_measurement_interval_recurrence: {self.name_plural_unit_measurement_interval_recurrence}
|
||||
count_interval_recurrence: {self.count_interval_recurrence}
|
||||
id_stripe_product: {self.id_stripe_product}
|
||||
does_expire_faster_once_unsealed: {self.does_expire_faster_once_unsealed}
|
||||
id_unit_measurement_interval_expiration_unsealed: {self.id_unit_measurement_interval_expiration_unsealed}
|
||||
symbol_unit_measurement_interval_expiration_unsealed: {self.symbol_unit_measurement_interval_expiration_unsealed}
|
||||
symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed: {self.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed}
|
||||
name_singular_unit_measurement_interval_expiration_unsealed: {self.name_singular_unit_measurement_interval_expiration_unsealed}
|
||||
name_plural_unit_measurement_interval_expiration_unsealed: {self.name_plural_unit_measurement_interval_expiration_unsealed}
|
||||
count_interval_expiration_unsealed: {self.count_interval_expiration_unsealed}
|
||||
has_variations: {self.has_variations}
|
||||
can_view: {self.can_view}
|
||||
can_edit: {self.can_edit}
|
||||
can_admin: {self.can_admin}
|
||||
@@ -378,3 +513,104 @@ class Permutation_Product_Variation_Link(db.Model):
|
||||
link.id_variation = query_row[3]
|
||||
return link
|
||||
"""
|
||||
|
||||
class Product_Permutation_Temp(db.Model, Store_Base):
|
||||
__tablename__: ClassVar[str] = 'Shop_Product_Permutation_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_permutation: int = db.Column(db.Integer, primary_key=True)
|
||||
id_product: int = db.Column(db.Integer)
|
||||
description: str = db.Column(db.String(4000))
|
||||
cost_local: float = db.Column(db.Float)
|
||||
id_currency_cost: int = db.Column(db.Integer)
|
||||
profit_local_min: float = db.Column(db.Float)
|
||||
latency_manufacture_days: int = db.Column(db.Integer)
|
||||
id_unit_measurement_quantity: int = db.Column(db.Integer)
|
||||
count_unit_measurement_per_quantity_step: int = db.Column(db.Float)
|
||||
quantity_min: int = db.Column(db.Integer)
|
||||
quantity_max: int = db.Column(db.Integer)
|
||||
quantity_stock: int = db.Column(db.Integer)
|
||||
is_subscription: bool = db.Column(db.Boolean)
|
||||
id_unit_measurement_interval_recurrence: int = db.Column(db.Integer)
|
||||
count_interval_recurrence: int = db.Column(db.Float)
|
||||
id_stripe_product: str = db.Column(db.String(50))
|
||||
does_expire_faster_once_unsealed: bool = db.Column(db.Boolean)
|
||||
id_unit_measurement_interval_expiration_unsealed: int = db.Column(db.Integer)
|
||||
count_interval_expiration_unsealed: int = db.Column(db.Integer)
|
||||
active: bool = db.Column(db.Boolean)
|
||||
guid: str = db.Column(db.String(36))
|
||||
|
||||
@classmethod
|
||||
def from_product_permutation(cls, product_permutation):
|
||||
row = cls()
|
||||
row.id_permutation = product_permutation.id_permutation
|
||||
row.id_product = product_permutation.id_product
|
||||
row.description = product_permutation.description
|
||||
row.cost_local = product_permutation.cost_local
|
||||
row.id_currency_cost = product_permutation.currency_cost.id_currency
|
||||
row.profit_local_min = product_permutation.profit_local_min
|
||||
row.latency_manufacture_days = product_permutation.latency_manufacture_days
|
||||
row.id_unit_measurement_quantity = product_permutation.id_unit_measurement_quantity
|
||||
row.count_unit_measurement_per_quantity_step = product_permutation.count_unit_measurement_per_quantity_step
|
||||
row.quantity_min = product_permutation.quantity_min
|
||||
row.quantity_max = product_permutation.quantity_max
|
||||
row.quantity_stock = product_permutation.quantity_stock
|
||||
row.is_subscription = product_permutation.is_subscription
|
||||
row.id_unit_measurement_interval_recurrence = product_permutation.id_unit_measurement_interval_recurrence
|
||||
row.count_interval_recurrence = product_permutation.count_interval_recurrence
|
||||
row.id_stripe_product = product_permutation.id_stripe_product
|
||||
row.does_expire_faster_once_unsealed = product_permutation.does_expire_faster_once_unsealed
|
||||
row.id_unit_measurement_interval_expiration_unsealed = product_permutation.id_unit_measurement_interval_expiration_unsealed
|
||||
row.count_interval_expiration_unsealed = product_permutation.count_interval_expiration_unsealed
|
||||
row.active = product_permutation.active
|
||||
return row
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_permutation: {self.id_permutation}
|
||||
id_product: {self.id_product}
|
||||
description: {self.description}
|
||||
cost_local: {self.cost_local}
|
||||
id_currency_cost: {self.id_currency_cost}
|
||||
profit_local_min: {self.profit_local_min}
|
||||
latency_manufacture_days: {self.latency_manufacture_days}
|
||||
id_unit_measurement_quantity: {self.id_unit_measurement_quantity}
|
||||
{Product_Permutation.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP}: {self.count_unit_measurement_per_quantity_step}
|
||||
quantity_min: {self.quantity_min}
|
||||
quantity_max: {self.quantity_max}
|
||||
quantity_stock: {self.quantity_stock}
|
||||
is_subscription: {self.is_subscription}
|
||||
id_unit_measurement_interval_recurrence: {self.id_unit_measurement_interval_recurrence}
|
||||
count_interval_recurrence: {self.count_interval_recurrence}
|
||||
id_stripe_product: {self.id_stripe_product}
|
||||
does_expire_faster_once_unsealed: {self.does_expire_faster_once_unsealed}
|
||||
id_unit_measurement_interval_expiration_unsealed: {self.id_unit_measurement_interval_expiration_unsealed}
|
||||
count_interval_expiration_unsealed: {self.count_interval_expiration_unsealed}
|
||||
active: {self.active}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
"""
|
||||
def to_json(self):
|
||||
return {
|
||||
self.ATTR_ID_PRODUCT_PERMUTATION: int(self.id_permutation),
|
||||
self.ATTR_ID_PRODUCT: int(self.id_product),
|
||||
self.FLAG_DESCRIPTION: self.description,
|
||||
Product_Permutation.FLAG_COST_LOCAL: float(self.cost_local),
|
||||
Product_Permutation.FLAG_CURRENCY_COST: int(self.id_currency_cost),
|
||||
Product_Permutation.FLAG_PROFIT_LOCAL_MIN: float(self.profit_local_min),
|
||||
Product_Permutation.FLAG_LATENCY_MANUFACTURE_DAYS: int(self.latency_manufacture_days),
|
||||
Product_Permutation.FLAG_UNIT_MEASUREMENT_QUANTITY: int(self.id_unit_measurement_quantity),
|
||||
Product_Permutation.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP: float(self.count_unit_measurement_per_quantity_step),
|
||||
self.FLAG_QUANTITY_MIN: float(self.quantity_min),
|
||||
self.FLAG_QUANTITY_MAX: float(self.quantity_max),
|
||||
Product_Permutation.FLAG_QUANTITY_STOCK: float(self.quantity_stock),
|
||||
Product_Permutation.FLAG_IS_SUBSCRIPTION: bool(self.is_subscription),
|
||||
Product_Permutation.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: int(self.id_unit_measurement_interval_recurrence) if self.id_unit_measurement_interval_recurrence != '' else None,
|
||||
Product_Permutation.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: float(self.count_interval_recurrence) if self.count_interval_recurrence != '' else None,
|
||||
Product_Permutation.FLAG_ID_STRIPE_PRODUCT: self.id_stripe_product,
|
||||
Product_Permutation.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED: bool(self.does_expire_faster_once_unsealed),
|
||||
Product_Permutation.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: int(self.id_unit_measurement_interval_expiration_unsealed) if self.id_unit_measurement_interval_expiration_unsealed != '' else None,
|
||||
Product_Permutation.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: float(self.count_interval_expiration_unsealed) if self.count_interval_expiration_unsealed != '' else None,
|
||||
self.FLAG_ACTIVE: bool(self.active),
|
||||
self.FLAG_GUID: self.guid
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -20,19 +20,21 @@ from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
class Product_Price(db.Model, Store_Base):
|
||||
ATTR_ID_PRODUCT_PRICE: ClassVar[str] = 'id-price'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_PRICE
|
||||
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_TEXT
|
||||
FLAG_VALUE_LOCAL_VAT_INCL: ClassVar[str] = 'value-local-vat-incl'
|
||||
FLAG_VALUE_LOCAL_VAT_EXCL: ClassVar[str] = 'value-local-vat-excl'
|
||||
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display-order-price'
|
||||
|
||||
id_price = db.Column(db.Integer, primary_key=True)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
"""
|
||||
id_currency = db.Column(db.Integer)
|
||||
code_currency = db.Column(db.String(50))
|
||||
name_currency = db.Column(db.String(255))
|
||||
symbol_currency = db.Column(db.String(50))
|
||||
"""
|
||||
id_region = db.Column(db.Integer)
|
||||
value_local_VAT_incl = db.Column(db.Float)
|
||||
value_local_VAT_excl = db.Column(db.Float)
|
||||
@@ -41,18 +43,23 @@ class Product_Price(db.Model, Store_Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
self.currency = None
|
||||
self.delivery_region = None
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue(cls, query_row):
|
||||
# _m = 'Product_Price.from_DB_get_many_product_catalogue'
|
||||
price = Product_Price()
|
||||
price = cls()
|
||||
price.id_price = query_row[0]
|
||||
price.id_permutation = query_row[1]
|
||||
price.id_product = query_row[2]
|
||||
price.id_category = query_row[3]
|
||||
price.currency = Currency.from_DB_get_many_product_price_and_discount_and_delivery_region(query_row)
|
||||
"""
|
||||
price.id_currency = query_row[4]
|
||||
price.code_currency = query_row[5]
|
||||
price.name_currency = query_row[6]
|
||||
price.symbol_currency = query_row[7]
|
||||
"""
|
||||
price.id_region = query_row[8]
|
||||
price.value_local_VAT_incl = query_row[9]
|
||||
price.value_local_VAT_excl = query_row[10]
|
||||
@@ -65,35 +72,26 @@ class Product_Price(db.Model, Store_Base):
|
||||
id_permutation: {self.id_permutation}
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
id_currency: {self.id_currency}
|
||||
code_currency: {self.code_currency}
|
||||
name_currency: {self.name_currency}
|
||||
symbol_currency: {self.symbol_currency}
|
||||
currency: {self.currency}
|
||||
id_region: {self.id_region}
|
||||
value_local (VAT incl): {self.value_local_VAT_incl}
|
||||
value_local (VAT excl): {self.value_local_VAT_excl}
|
||||
display_order (UID): {self.display_order}
|
||||
{self.FLAG_TEXT}: {self.currency.symbol} {self.value_local_VAT_incl}
|
||||
'''
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
self.ATTR_ID_PRODUCT_PRICE: {self.id_price},
|
||||
self.ATTR_ID_PRODUCT_PERMUTATION: {self.id_permutation},
|
||||
self.ATTR_ID_PRODUCT: {self.id_product},
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: {self.id_category},
|
||||
Currency.ATTR_ID_CURRENCY: {self.id_currency},
|
||||
Currency.FLAG_CODE: {self.code_currency},
|
||||
Currency.FLAG_NAME: {self.name_currency},
|
||||
Currency.FLAG_SYMBOL: {self.symbol_currency},
|
||||
Delivery_Region.ATTR_ID_REGION: {self.id_region},
|
||||
self.FLAG_VALUE_LOCAL_VAT_INCL: {self.value_local_VAT_incl},
|
||||
self.FLAG_VALUE_LOCAL_VAT_EXCL: {self.value_local_VAT_excl},
|
||||
self.FLAG_DISPLAY_ORDER: {self.display_order}
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_price,
|
||||
'text': f'{self.symbol_currency} {self.value_local_VAT_incl}'
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PRODUCT_PRICE: self.id_price,
|
||||
self.ATTR_ID_PRODUCT_PERMUTATION: self.id_permutation,
|
||||
self.ATTR_ID_PRODUCT: self.id_product,
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
|
||||
self.FLAG_CURRENCY: self.currency.to_json(),
|
||||
Delivery_Region.ATTR_ID_DELIVERY_REGION: self.id_region,
|
||||
self.FLAG_VALUE_LOCAL_VAT_INCL: self.value_local_VAT_incl,
|
||||
self.FLAG_VALUE_LOCAL_VAT_EXCL: self.value_local_VAT_excl,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@@ -103,11 +101,8 @@ class Product_Price(db.Model, Store_Base):
|
||||
price.id_permutation = json[cls.ATTR_ID_PRODUCT_PERMUTATION]
|
||||
price.id_product = json[cls.ATTR_ID_PRODUCT]
|
||||
price.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
price.id_currency = json[Currency.ATTR_ID_CURRENCY]
|
||||
price.code_currency = json[Currency.FLAG_CODE]
|
||||
price.name_currency = json[Currency.FLAG_NAME]
|
||||
price.symbol_currency = json[Currency.FLAG_SYMBOL]
|
||||
price.id_region = json[Delivery_Region.ATTR_ID_REGION]
|
||||
price.currency = Currency.from_json(json)
|
||||
price.id_region = json[Delivery_Region.ATTR_ID_DELIVERY_REGION]
|
||||
price.value_local_VAT_incl = json[cls.FLAG_VALUE_LOCAL_VAT_INCL]
|
||||
price.value_local_VAT_excl = json[cls.FLAG_VALUE_LOCAL_VAT_EXCL]
|
||||
price.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
|
||||
@@ -19,124 +19,103 @@ Business object for product variation
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from business_objects.store.product_variation_type import Product_Variation_Type
|
||||
from extensions import db
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
from pydantic import BaseModel
|
||||
from itertools import filterfalse
|
||||
from operator import attrgetter
|
||||
|
||||
|
||||
# CLASSES
|
||||
class Product_Variation(db.Model, Store_Base):
|
||||
KEY_ACTIVE_VARIATION: ClassVar[str] = 'active_variation'
|
||||
KEY_ACTIVE_VARIATION_TYPE: ClassVar[str] = 'active_variation_type'
|
||||
KEY_CODE_VARIATION: ClassVar[str] = 'code_variation'
|
||||
KEY_CODE_VARIATION_TYPE: ClassVar[str] = 'code_variation_type'
|
||||
KEY_DISPLAY_ORDER_VARIATION: ClassVar[str] = 'display_order_variation'
|
||||
KEY_DISPLAY_ORDER_VARIATION_TYPE: ClassVar[str] = 'display_order_variation_type'
|
||||
KEY_NAME_VARIATION: ClassVar[str] = 'name_variation'
|
||||
KEY_NAME_VARIATION_TYPE: ClassVar[str] = 'name_variation_type'
|
||||
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_VARIATION
|
||||
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME
|
||||
|
||||
id_variation = db.Column(db.Integer, primary_key=True)
|
||||
code_variation = db.Column(db.String(50))
|
||||
name_variation = db.Column(db.String(255))
|
||||
active_variation = db.Column(db.Boolean)
|
||||
display_order_variation = db.Column(db.Integer)
|
||||
id_type = db.Column(db.Integer)
|
||||
code_variation_type = db.Column(db.String(50))
|
||||
name_variation_type = db.Column(db.String(255))
|
||||
name_plural_variation_type = db.Column(db.String(255))
|
||||
active_variation_type = db.Column(db.Boolean)
|
||||
display_order_variation_type = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
code = db.Column(db.String(50))
|
||||
name = db.Column(db.String(255))
|
||||
display_order = db.Column(db.Integer)
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
id_permutation = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.variation_type = None
|
||||
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
variation = Product_Variation.from_DB_variation(query_row)
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue(cls, query_row):
|
||||
variation = Product_Variation.from_DB_get_many_product_variation(query_row)
|
||||
variation.id_product = query_row[11]
|
||||
variation.id_permutation = query_row[12]
|
||||
variation.id_category = query_row[13]
|
||||
variation.variation_type = Product_Variation_Type.from_DB_get_many_product_catalogue(query_row)
|
||||
return variation
|
||||
|
||||
def from_DB_variation(query_row):
|
||||
_m = 'Product_Variation.from_DB_variation'
|
||||
variation = Product_Variation()
|
||||
@classmethod
|
||||
def from_DB_get_many_product_variation(cls, query_row):
|
||||
variation = cls()
|
||||
variation.id_variation = query_row[0]
|
||||
variation.code_variation = query_row[1]
|
||||
variation.name_variation = query_row[2]
|
||||
variation.active_variation = av.input_bool(query_row[3], 'active_variation', _m)
|
||||
variation.display_order_variation = query_row[4]
|
||||
variation.id_type = query_row[5]
|
||||
variation.code_variation_type = query_row[6]
|
||||
variation.name_variation_type = query_row[7]
|
||||
variation.name_plural_variation_type = query_row[8]
|
||||
variation.active_variation_type = av.input_bool(query_row[9], 'active_variation', _m)
|
||||
variation.display_order_variation_type = query_row[10]
|
||||
variation.id_type = query_row[1]
|
||||
variation.code = query_row[2]
|
||||
variation.name = query_row[3]
|
||||
variation.display_order = query_row[4]
|
||||
variation.active = av.input_bool(query_row[5], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_get_many_product_variation')
|
||||
return variation
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
variation = cls()
|
||||
variation.id_variation = json[cls.ATTR_ID_VARIATION]
|
||||
variation.id_variation = json[cls.ATTR_ID_PRODUCT_VARIATION]
|
||||
variation.code = json[cls.FLAG_CODE]
|
||||
variation.name = json[cls.FLAG_NAME]
|
||||
variation.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
variation.active = json[cls.FLAG_ACTIVE]
|
||||
variation.id_permutation = json[cls.ATTR_ID_PRODUCT_PERMUTATION]
|
||||
variation.id_product = json[cls.ATTR_ID_PRODUCT]
|
||||
variation.id_permutation = json[cls.ATTR_ID_PERMUTATION]
|
||||
variation.id_category = json[cls.ATTR_ID_CATEGORY]
|
||||
variation.name_variation_type = json[cls.KEY_NAME_VARIATION_TYPE]
|
||||
variation.name_variation = json[cls.KEY_NAME_VARIATION]
|
||||
variation.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
return variation
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_variation}
|
||||
id_product: {self.id_product}
|
||||
{self.__class__.__name__}
|
||||
id_variation: {self.id_variation}
|
||||
id_type: {self.id_type}
|
||||
code: {self.code}
|
||||
name: {self.name}
|
||||
display_order: {self.display_order}
|
||||
active: {self.active}
|
||||
id_permutation: {self.id_permutation}
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
code_variation_type: {self.code_variation_type}
|
||||
name_variation_type: {self.name_variation_type}
|
||||
code_variation: {self.code_variation}
|
||||
name_variation: {self.name_variation}
|
||||
active_variation: {self.active_variation}
|
||||
active_variation_type: {self.active_variation_type}
|
||||
display_order_variation: {self.display_order_variation}
|
||||
display_order_variation_type: {self.display_order_variation_type}
|
||||
variation_type: {self.variation_type}
|
||||
'''
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PRODUCT_VARIATION: self.id_variation,
|
||||
self.ATTR_ID_PRODUCT_VARIATION_TYPE: self.id_type,
|
||||
self.FLAG_CODE: self.code,
|
||||
self.FLAG_NAME: self.name,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
self.ATTR_ID_PRODUCT: self.id_product,
|
||||
self.ATTR_ID_PRODUCT_PERMUTATION: self.id_permutation,
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
|
||||
self.ATTR_ID_PRODUCT_VARIATION_TYPE: self.id_type,
|
||||
self.KEY_CODE_VARIATION_TYPE: self.code_variation_type,
|
||||
self.KEY_CODE_VARIATION: self.code_variation,
|
||||
self.KEY_DISPLAY_ORDER_VARIATION_TYPE: self.display_order_variation_type,
|
||||
self.KEY_DISPLAY_ORDER_VARIATION: self.display_order_variation,
|
||||
self.KEY_NAME_VARIATION_TYPE: self.name_variation_type,
|
||||
self.KEY_NAME_VARIATION: self.name_variation,
|
||||
self.KEY_ACTIVE_VARIATION_TYPE: self.active_variation_type,
|
||||
self.KEY_ACTIVE_VARIATION: self.active_variation,
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_variation,
|
||||
'text': self.name_variation
|
||||
}
|
||||
|
||||
def to_json_variation_type(self):
|
||||
return {
|
||||
self.ATTR_ID_PRODUCT_VARIATION_TYPE: self.id_type,
|
||||
self.KEY_CODE_VARIATION_TYPE: self.code_variation_type,
|
||||
self.KEY_DISPLAY_ORDER_VARIATION_TYPE: self.display_order_variation_type,
|
||||
self.KEY_NAME_VARIATION_TYPE: self.name_variation_type,
|
||||
self.KEY_ACTIVE_VARIATION_TYPE: self.active_variation_type,
|
||||
'text': self.name
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Product_Variation_Filters():
|
||||
get_all_variation_type: bool
|
||||
@@ -198,30 +177,35 @@ class Product_Variation_Filters():
|
||||
get_first_variation = False,
|
||||
ids_variation = ''
|
||||
)
|
||||
|
||||
class Product_Variation_List(BaseModel):
|
||||
|
||||
|
||||
class Product_Variation_Container(BaseModel):
|
||||
variation_types: list = []
|
||||
variations: list = []
|
||||
|
||||
def add_product_variation_type(self, variation_type):
|
||||
av.val_instance(variation_type, 'variation_type', 'Product_Variation_Container.add_product_variation_type', Product_Variation_Type)
|
||||
self.variations.append(variation_type)
|
||||
def add_product_variation(self, variation):
|
||||
av.val_instance(variation, 'variation', 'Product_Variation_List.add_product_variation', Product_Variation)
|
||||
av.val_instance(variation, 'variation', 'Product_Variation_Container.add_product_variation', Product_Variation)
|
||||
if variation.variation_type is None:
|
||||
variation_type = next(filterfalse(lambda x: x.id_type != variation.id_type, self.variation_types), None)
|
||||
if variation_type is not None:
|
||||
variation.variation_type = variation_type
|
||||
self.variations.append(variation)
|
||||
|
||||
def __repr__(self):
|
||||
return f'variations: {self.variations}'
|
||||
return f'Product_Variation_Container:\nvariations_types: {self.variation_types}\nvariations: {self.variations}'
|
||||
|
||||
def to_list_variations(self):
|
||||
def to_list_variation_options(self):
|
||||
list_variations = []
|
||||
for variation in self.variations:
|
||||
list_variations.append(variation.to_json())
|
||||
list_variations.append(variation.to_json_option())
|
||||
print(f'list_variations: {list_variations}')
|
||||
return list_variations
|
||||
|
||||
def to_list_variation_types(self):
|
||||
def to_list_variation_type_options(self):
|
||||
list_variation_types = []
|
||||
list_variation_ids = []
|
||||
for variation in self.variations:
|
||||
if variation.id_type not in list_variation_ids:
|
||||
list_variation_ids.append(variation.id_type)
|
||||
list_variation_types.append(variation.to_json_variation_type())
|
||||
for variation_type in self.variation_types:
|
||||
list_variation_types.append(variation_type.to_json_option())
|
||||
return list_variation_types
|
||||
|
||||
@@ -55,20 +55,42 @@ class Product_Variation_Tree():
|
||||
is_equal = (sz_me == sz_other)
|
||||
if is_equal:
|
||||
for index_type in range(sz_me):
|
||||
if sz_me[index_type] != sz_other[index_type]:
|
||||
if my_type_list[index_type] != other_type_list[index_type]:
|
||||
is_equal = False
|
||||
break
|
||||
return is_equal
|
||||
def from_product_permutation(product_permutation):
|
||||
@classmethod
|
||||
def from_product_permutation(cls, product_permutation):
|
||||
depth_max = len(product_permutation.variations)
|
||||
node_root = Product_Variation_Tree_Node.from_variation_and_node_parent(product_permutation.variations[0], None)
|
||||
node = node_root
|
||||
for depth in range(depth_max - 1):
|
||||
node = Product_Variation_Tree_Node.from_variation_and_node_parent(product_permutation.variations[depth + 1], node)
|
||||
return Product_Variation_Tree.from_node_root(node_root)
|
||||
def from_product_variation(product_variation):
|
||||
return cls.from_node_root(node_root)
|
||||
@classmethod
|
||||
def from_product_variation(cls, product_variation):
|
||||
node_root = Product_Variation_Tree_Node.from_variation_and_node_parent(product_variation, None)
|
||||
return Product_Variation_Tree.from_node_root(node_root)
|
||||
return cls.from_node_root(node_root)
|
||||
@classmethod
|
||||
def from_product_variations(cls, product_variations):
|
||||
node_root = Product_Variation_Tree_Node.from_variation_and_node_parent(product_variations[0], None)
|
||||
tree = cls.from_node_root(node_root)
|
||||
if len(product_variations) > 1:
|
||||
for variation in product_variations[1:]:
|
||||
tree.add_product_variation(variation)
|
||||
return tree
|
||||
@classmethod
|
||||
def from_json_str(cls, json_str):
|
||||
variations = []
|
||||
for json_variation in json_str.split(','):
|
||||
parts = json_variation.split(':')
|
||||
if len(parts) != 2: continue
|
||||
variation = Product_Variation()
|
||||
variation.id_type = parts[0]
|
||||
variation.id_variation = parts[1]
|
||||
variations.append(variation)
|
||||
return cls.from_product_variations(variations)
|
||||
"""
|
||||
def get_name_variations(self):
|
||||
node = self.node_root
|
||||
name = node.variation.name_variation_type
|
||||
@@ -78,6 +100,7 @@ class Product_Variation_Tree():
|
||||
name += f', {node.variation.name_variation_type}'
|
||||
at_leaf_node = node.is_leaf()
|
||||
return name
|
||||
"""
|
||||
def get_node_leaf(self):
|
||||
node = self.node_root
|
||||
at_leaf_node = node.is_leaf()
|
||||
@@ -102,8 +125,64 @@ class Product_Variation_Tree():
|
||||
variations = []
|
||||
node = self.node_root
|
||||
at_leaf_node = node.is_leaf()
|
||||
variations.append(node.variation)
|
||||
while not at_leaf_node:
|
||||
variations.append(node.variation)
|
||||
node = node.nodes_child[0]
|
||||
at_leaf_node = node.is_leaf()
|
||||
return variations
|
||||
variations.append(node.variation)
|
||||
return variations
|
||||
def to_preview_str(self):
|
||||
print(f'Product_Variation_Tree.to_preview_str')
|
||||
variations = self.get_product_variations()
|
||||
print(f'variations: {variations}')
|
||||
preview_str = ''
|
||||
for variation in variations:
|
||||
is_first = (preview_str == '')
|
||||
preview_str += f'{variation.variation_type.name_singular}: {variation.name}'
|
||||
if is_first:
|
||||
preview_str += '\n'
|
||||
print(f'preview_str: {preview_str}')
|
||||
return preview_str
|
||||
def to_json(self):
|
||||
variations = self.get_product_variations()
|
||||
json_variations = []
|
||||
for variation in variations:
|
||||
json_variations.append(variation.to_json())
|
||||
return json_variations
|
||||
def to_variation_id_pairs_str(self):
|
||||
variations = self.get_product_variations()
|
||||
pairs_str = ''
|
||||
for variation in variations:
|
||||
pairs_str += f'{variation.id_type}:{variation.id_variation},'
|
||||
return pairs_str
|
||||
"""
|
||||
class Product_Variation_Container(BaseModel):
|
||||
variation_types: list = []
|
||||
variations: list = []
|
||||
|
||||
def add_product_variation_type(self, variation_type):
|
||||
av.val_instance(variation_type, 'variation_type', 'Product_Variation_Container.add_product_variation_type', Product_Variation_Type)
|
||||
self.variations.append(variation_type)
|
||||
def add_product_variation(self, variation):
|
||||
av.val_instance(variation, 'variation', 'Product_Variation_Container.add_product_variation', Product_Variation)
|
||||
if variation.variation_type is None:
|
||||
variation_type = next(filterfalse(lambda x: x.id_type != variation.id_type, self.variation_types), None)
|
||||
if variation_type is not None:
|
||||
variation.variation_type = variation_type
|
||||
self.variations.append(variation)
|
||||
|
||||
def __repr__(self):
|
||||
return f'Product_Variation_Container:\nvariations_types: {self.variation_types}\nvariations: {self.variations}'
|
||||
|
||||
def to_list_variation_options(self):
|
||||
list_variations = []
|
||||
for variation in self.variations:
|
||||
list_variations.append(variation.to_json_option())
|
||||
print(f'list_variations: {list_variations}')
|
||||
return list_variations
|
||||
def to_list_variation_type_options(self):
|
||||
list_variation_types = []
|
||||
for variation_type in self.variation_types:
|
||||
list_variation_types.append(variation_type.to_json_option())
|
||||
return list_variation_types
|
||||
"""
|
||||
103
business_objects/store/product_variation_type.py
Normal file
103
business_objects/store/product_variation_type.py
Normal file
@@ -0,0 +1,103 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Product_Variation Business Object
|
||||
|
||||
Description:
|
||||
Business object for product variation
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# VARIABLE INSTANTIATION
|
||||
# CLASSES
|
||||
# METHODS
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
from pydantic import BaseModel
|
||||
from itertools import filterfalse
|
||||
from operator import attrgetter
|
||||
|
||||
class Product_Variation_Type(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_VARIATION_TYPE
|
||||
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME_SINGULAR
|
||||
|
||||
id_type = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
name_singular = db.Column(db.String(255))
|
||||
name_plural = db.Column(db.String(255))
|
||||
display_order = db.Column(db.Integer)
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue(cls, query_row):
|
||||
variation_type = cls()
|
||||
variation_type.id_type = query_row[1]
|
||||
variation_type.code = query_row[6]
|
||||
variation_type.name_singular = query_row[7]
|
||||
variation_type.name_plural = query_row[8]
|
||||
variation_type.display_order = query_row[9]
|
||||
variation_type.active = av.input_bool(query_row[10], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_get_many_product_catalogue')
|
||||
return variation_type
|
||||
|
||||
@classmethod
|
||||
def from_DB_get_many_product_variation(cls, query_row):
|
||||
variation_type = cls()
|
||||
variation_type.id_type = query_row[0]
|
||||
variation_type.code = query_row[1]
|
||||
variation_type.name_singular = query_row[2]
|
||||
variation_type.name_plural = query_row[3]
|
||||
variation_type.display_order = query_row[4]
|
||||
variation_type.active = av.input_bool(query_row[5], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_get_many_product_variation')
|
||||
return variation_type
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
variation_type = cls()
|
||||
variation_type.id_type = json[cls.ATTR_ID_PRODUCT_VARIATION_TYPE]
|
||||
variation_type.code = json[cls.FLAG_CODE]
|
||||
variation_type.name_singular = json[cls.FLAG_NAME_SINGULAR]
|
||||
variation_type.name_plural = json[cls.FLAG_NAME_PLURAL]
|
||||
variation_type.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
variation_type.active = json[cls.FLAG_ACTIVE]
|
||||
return variation_type
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.__class__.__name__}
|
||||
id_type: {self.id_type}
|
||||
code: {self.code}
|
||||
name_singular: {self.name_singular}
|
||||
name_plural: {self.name_plural}
|
||||
display_order: {self.display_order}
|
||||
active: {self.active}
|
||||
'''
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PRODUCT_VARIATION_TYPE: self.id_type,
|
||||
self.FLAG_CODE: self.code,
|
||||
self.FLAG_NAME_SINGULAR: self.name_singular,
|
||||
self.FLAG_NAME_PLURAL: self.name_plural,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_type,
|
||||
'text': self.name_singular
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ from datetime import datetime
|
||||
|
||||
class Stock_Item(db.Model, Store_Base):
|
||||
ATTR_ID_CURRENCY_COST: ClassVar[str] = f'{Store_Base.ATTR_ID_CURRENCY}-cost'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_CURRENCY
|
||||
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME
|
||||
FLAG_DATE_CONSUMED: ClassVar[str] = 'date-consumed'
|
||||
FLAG_DATE_EXPIRATION: ClassVar[str] = 'date-expiration'
|
||||
FLAG_DATE_PURCHASED: ClassVar[str] = 'date-purchased'
|
||||
@@ -175,6 +177,7 @@ class Stock_Item(db.Model, Store_Base):
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PRODUCT: {self.id_product},
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: {self.id_category},
|
||||
self.FLAG_NAME: {self.name},
|
||||
@@ -183,8 +186,8 @@ class Stock_Item(db.Model, Store_Base):
|
||||
self.FLAG_CAN_EDIT: {self.can_edit},
|
||||
self.FLAG_CAN_ADMIN: {self.can_admin},
|
||||
self.FLAG_HAS_VARIATIONS: {self.has_variations},
|
||||
self.FLAG_PERMUTATIONS: {self.permutations},
|
||||
self.FLAG_VARIATION_TREES: {self.variation_trees},
|
||||
self.FLAG_PRODUCT_PERMUTATION: {self.permutations},
|
||||
self.FLAG_PRODUCT_VARIATION_TREES: {self.variation_trees},
|
||||
}
|
||||
def has_permutations(self):
|
||||
return len(self.permutations) > 0
|
||||
|
||||
@@ -12,6 +12,7 @@ Abstract business object for store objects
|
||||
|
||||
# internal
|
||||
# from helpers.DEPRECATED.helper_abc import Interface_ABC
|
||||
from business_objects.base import Base
|
||||
from extensions import db
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
@@ -55,40 +56,33 @@ class I_Store_Base():
|
||||
""
|
||||
"""
|
||||
|
||||
class Store_Base():
|
||||
ATTR_ID_ACCESS_LEVEL: ClassVar[str] = 'id_access_level'
|
||||
ATTR_ID_CURRENCY: ClassVar[str] = 'id_currency'
|
||||
class Store_Base(Base):
|
||||
# ATTR_ID_CURRENCY_COST: ClassVar[str] = 'id_currency_cost'
|
||||
ATTR_ID_DELIVERY_REGION: ClassVar[str] = 'id_delivery_region'
|
||||
ATTR_ID_DISCOUNT: ClassVar[str] = 'id_discount'
|
||||
ATTR_ID_IMAGE: ClassVar[str] = 'id_image'
|
||||
ATTR_ID_LOCATION_STORAGE: ClassVar[str] = 'id_location_storage'
|
||||
ATTR_ID_PRODUCT: ClassVar[str] = 'id_product'
|
||||
ATTR_ID_PRODUCT_CATEGORY: ClassVar[str] = 'id_category'
|
||||
ATTR_ID_PRODUCT_IMAGE: ClassVar[str] = 'id_image'
|
||||
ATTR_ID_PRODUCT_PERMUTATION: ClassVar[str] = 'id_permutation'
|
||||
ATTR_ID_PRODUCT_PRICE: ClassVar[str] = 'id_price'
|
||||
ATTR_ID_PRODUCT_VARIATION: ClassVar[str] = 'id_variation'
|
||||
ATTR_ID_PRODUCT_VARIATION_TYPE: ClassVar[str] = 'id_variation_type'
|
||||
ATTR_ID_PRODUCT_VARIATION_TYPE: ClassVar[str] = 'id_type'
|
||||
ATTR_ID_STOCK_ITEM: ClassVar[str] = 'id_stock_item'
|
||||
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = 'access_level_required'
|
||||
FLAG_ACTIVE: ClassVar[str] = 'active'
|
||||
FLAG_CAN_ADMIN: ClassVar[str] = 'can_admin'
|
||||
FLAG_CAN_EDIT: ClassVar[str] = 'can_edit'
|
||||
FLAG_CAN_VIEW: ClassVar[str] = 'can_view'
|
||||
FLAG_CODE: ClassVar[str] = 'code'
|
||||
FLAG_DESCRIPTION: ClassVar[str] = 'description'
|
||||
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display_order'
|
||||
FLAG_CURRENCY: ClassVar[str] = 'currency'
|
||||
FLAG_DELIVERY_OPTION: ClassVar[str] = 'delivery_option'
|
||||
FLAG_HAS_VARIATIONS: ClassVar[str] = 'has_variations'
|
||||
FLAG_IS_NOT_EMPTY: ClassVar[str] = 'is_not_empty'
|
||||
FLAG_KEY_PRIMARY: ClassVar[str] = 'key_primary'
|
||||
FLAG_NAME: ClassVar[str] = 'name'
|
||||
FLAG_PERMUTATIONS: ClassVar[str] = 'permutations'
|
||||
FLAG_PRIORITY: ClassVar[str] = 'priority'
|
||||
FLAG_ROWS: ClassVar[str] = 'rows'
|
||||
FLAG_VARIATION_TREES: ClassVar[str] = 'variation_trees'
|
||||
@classmethod
|
||||
def output_bool(cls, value):
|
||||
return av.input_bool(value, f'{cls.__name__} bool attribute', f'{cls.__name__}.output_bool')
|
||||
@staticmethod
|
||||
def convert_list_objects_to_list_options(objects):
|
||||
return [object.to_json_option() for object in objects]
|
||||
FLAG_IS_OUT_OF_STOCK: ClassVar[str] = 'is_out_of_stock'
|
||||
FLAG_PRODUCT: ClassVar[str] = 'product'
|
||||
FLAG_PRODUCT_CATEGORY: ClassVar[str] = 'product_category'
|
||||
FLAG_PRODUCT_IMAGE: ClassVar[str] = 'product_image'
|
||||
FLAG_PRODUCT_PERMUTATION: ClassVar[str] = 'product_permutation'
|
||||
FLAG_PRODUCT_PRICE: ClassVar[str] = 'product_price'
|
||||
FLAG_PRODUCT_VARIATION: ClassVar[str] = 'product_variation'
|
||||
FLAG_PRODUCT_VARIATIONS: ClassVar[str] = f'{FLAG_PRODUCT_VARIATION}s'
|
||||
FLAG_PRODUCT_VARIATION_TYPE: ClassVar[str] = 'product_variation_type'
|
||||
FLAG_QUANTITY_MIN: ClassVar[str] = 'quantity_min'
|
||||
FLAG_QUANTITY_MAX: ClassVar[str] = 'quantity_max'
|
||||
FLAG_TEXT: ClassVar[str] = 'text'
|
||||
FLAG_VALUE_TEXT: ClassVar[str] = 'value_text'
|
||||
|
||||
160
business_objects/unit_measurement.py
Normal file
160
business_objects/unit_measurement.py
Normal file
@@ -0,0 +1,160 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Unit of Measurement Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||
from extensions import db
|
||||
# from forms.forms import Form_Filters_User
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Unit_Measurement(SQLAlchemy_ABC, Base):
|
||||
ATTR_ID_UNIT_MEASUREMENT: ClassVar[str] = 'id_unit_measurement'
|
||||
FLAG_IS_BASE_UNIT: ClassVar[str] = 'is_base_unit'
|
||||
FLAG_IS_UNIT_OF_DISTANCE: ClassVar[str] = 'is_unit_of_distance'
|
||||
FLAG_IS_UNIT_OF_MASS: ClassVar[str] = 'is_unit_of_mass'
|
||||
FLAG_IS_UNIT_OF_TIME: ClassVar[str] = 'is_unit_of_time'
|
||||
FLAG_IS_UNIT_OF_VOLUME: ClassVar[str] = 'is_unit_of_volume'
|
||||
FLAG_NAME_PLURAL: ClassVar[str] = 'name_plural'
|
||||
FLAG_NAME_SINGULAR: ClassVar[str] = 'name_singular'
|
||||
FLAG_SYMBOL: ClassVar[str] = 'symbol'
|
||||
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX: ClassVar[str] = 'symbol_is_suffix_not_prefix'
|
||||
# KEY_UNIT_MEASUREMENT: ClassVar[str] = 'unit_of_measurement'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_ID_UNIT_MEASUREMENT
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = FLAG_NAME_SINGULAR
|
||||
|
||||
id_unit_measurement = db.Column(db.Integer, primary_key=True)
|
||||
name_singular = db.Column(db.String(255))
|
||||
name_plural = db.Column(db.String(256))
|
||||
symbol = db.Column(db.String(50))
|
||||
symbol_is_suffix_not_prefix = db.Column(db.Boolean)
|
||||
is_base_unit = db.Column(db.Boolean)
|
||||
is_unit_of_distance = db.Column(db.Boolean)
|
||||
is_unit_of_mass = db.Column(db.Boolean)
|
||||
is_unit_of_time = db.Column(db.Boolean)
|
||||
is_unit_of_volume = db.Column(db.Boolean)
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
def from_DB_unit_measurement(query_row):
|
||||
_m = 'Unit_Measurement.from_DB_unit_measurement'
|
||||
unit = Unit_Measurement()
|
||||
unit.id_unit_measurement = query_row[0]
|
||||
unit.name_singular = query_row[1]
|
||||
unit.name_plural = query_row[2]
|
||||
unit.symbol = query_row[3]
|
||||
unit.symbol_is_suffix_not_prefix = av.input_bool(query_row[4], 'symbol_is_suffix_not_prefix', _m)
|
||||
unit.is_base_unit = av.input_bool(query_row[5], 'is_base_unit', _m)
|
||||
unit.is_unit_of_distance = av.input_bool(query_row[6], 'is_unit_of_distance', _m)
|
||||
unit.is_unit_of_mass = av.input_bool(query_row[7], 'is_unit_of_mass', _m)
|
||||
unit.is_unit_of_time = av.input_bool(query_row[8], 'is_unit_of_time', _m)
|
||||
unit.is_unit_of_volume = av.input_bool(query_row[9], 'is_unit_of_volume', _m)
|
||||
unit.active = av.input_bool(query_row[10], 'active', _m)
|
||||
return unit
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_UNIT_MEASUREMENT: self.id_unit_measurement,
|
||||
self.FLAG_NAME_SINGULAR: self.name_singular,
|
||||
self.FLAG_NAME_PLURAL: self.name_plural,
|
||||
self.FLAG_SYMBOL: self.symbol,
|
||||
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX: self.symbol_is_suffix_not_prefix,
|
||||
self.FLAG_IS_BASE_UNIT: self.is_base_unit,
|
||||
self.FLAG_IS_UNIT_OF_DISTANCE: self.is_unit_of_distance,
|
||||
self.FLAG_IS_UNIT_OF_MASS: self.is_unit_of_mass,
|
||||
self.FLAG_IS_UNIT_OF_TIME: self.is_unit_of_time,
|
||||
self.FLAG_IS_UNIT_OF_VOLUME: self.is_unit_of_volume,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
print(f' Unit_Measurement.from_json: {json}')
|
||||
unit = cls()
|
||||
unit.id_unit_measurement = json[cls.ATTR_ID_UNIT_MEASUREMENT]
|
||||
unit.name_singular = json[cls.FLAG_NAME_SINGULAR]
|
||||
unit.name_plural = json[cls.FLAG_NAME_PLURAL]
|
||||
unit.symbol = json[cls.FLAG_SYMBOL]
|
||||
unit.symbol_is_suffix_not_prefix = json[cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX]
|
||||
unit.is_base_unit = json[cls.FLAG_IS_BASE_UNIT]
|
||||
unit.is_unit_of_distance = json[cls.FLAG_IS_UNIT_OF_DISTANCE]
|
||||
unit.is_unit_of_mass = json[cls.FLAG_IS_UNIT_OF_MASS]
|
||||
unit.is_unit_of_time = json[cls.FLAG_IS_UNIT_OF_TIME]
|
||||
unit.is_unit_of_volume = json[cls.FLAG_IS_UNIT_OF_VOLUME]
|
||||
unit.active = json[cls.FLAG_ACTIVE]
|
||||
return unit
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_unit_of_measurement: {self.id_unit_measurement},
|
||||
name_singular: {self.name_singular},
|
||||
name_plural: {self.name_plural},
|
||||
symbol: {self.symbol},
|
||||
symbol_is_suffix_not_prefix: {self.symbol_is_suffix_not_prefix},
|
||||
is_base_unit: {self.is_base_unit},
|
||||
is_unit_of_distance: {self.is_unit_of_distance},
|
||||
is_unit_of_mass: {self.is_unit_of_mass},
|
||||
is_unit_of_time: {self.is_unit_of_time},
|
||||
is_unit_of_volume: {self.is_unit_of_volume},
|
||||
active: {self.active}
|
||||
'''
|
||||
|
||||
"""
|
||||
@dataclass
|
||||
class Filters_Unit_Measurement():
|
||||
active_only: bool = False
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
'a_get_all_user': self.get_all_user,
|
||||
'a_get_inactive_user': self.get_inactive_user,
|
||||
'a_get_first_user_only': self.get_first_user_only,
|
||||
'a_ids_user': self.ids_user,
|
||||
'a_ids_user_auth0': self.ids_user_auth0,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def from_form(form):
|
||||
av.val_instance(form, 'form', 'User_Filters.from_form', Form_Filters_User)
|
||||
get_inactive = av.input_bool(form.active.data, "active", "User_Filters.from_form")
|
||||
id_user = form.id_user.data
|
||||
return User_Filters(
|
||||
get_all_user = (id_user is None),
|
||||
get_inactive_user = get_inactive,
|
||||
get_first_user_only = False,
|
||||
ids_user = id_user,
|
||||
ids_user_auth0 = '',
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def from_user(user):
|
||||
av.val_instance(user, 'user', 'User_Filters.from_user', User)
|
||||
return User_Filters(
|
||||
get_all_user = (user.id_user is None and user.id_user_auth0 is None),
|
||||
get_inactive_user = False,
|
||||
get_first_user_only = False,
|
||||
ids_user = user.id_user,
|
||||
ids_user_auth0 = user.id_user_auth0,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_default(datastore_store):
|
||||
user = datastore_store.get_login_user()
|
||||
return User_Filters(
|
||||
get_all_user = False,
|
||||
get_inactive_user = False,
|
||||
get_first_user_only = False,
|
||||
ids_user = user.id_user,
|
||||
ids_user_auth0 = '',
|
||||
)
|
||||
"""
|
||||
@@ -8,6 +8,7 @@ Feature: User Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
import lib.argument_validation as av
|
||||
from forms.forms import Form_Filters_User
|
||||
from extensions import db
|
||||
@@ -16,8 +17,10 @@ from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class User(db.Model):
|
||||
class User(db.Model, Base):
|
||||
KEY_USER: ClassVar[str] = 'authorisedUser' # 'user' already used
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_ID_USER
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'email'
|
||||
|
||||
id_user = db.Column(db.Integer, primary_key=True)
|
||||
id_user_auth0 = db.Column(db.String(255))
|
||||
@@ -200,8 +203,9 @@ class User_Filters():
|
||||
ids_access_level: str
|
||||
ids_product: str
|
||||
|
||||
def to_json(self):
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
'a_ids_user': self.ids_user,
|
||||
'a_get_inactive_users': self.get_inactive_users,
|
||||
'a_ids_permission': self.ids_permission,
|
||||
|
||||
BIN
controllers/__pycache__/core.cpython-312.pyc
Normal file
BIN
controllers/__pycache__/core.cpython-312.pyc
Normal file
Binary file not shown.
@@ -12,6 +12,7 @@ Initializes the Flask application, sets the configuration based on the environme
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
from forms.forms import Form_Contact
|
||||
from models.model_view_admin_home import Model_View_Admin_Home
|
||||
from models.model_view_contact import Model_View_Contact
|
||||
@@ -44,7 +45,10 @@ def home():
|
||||
@routes_core.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['GET'])
|
||||
def contact():
|
||||
try:
|
||||
user = DataStore_Base.get_user_session()
|
||||
form = Form_Contact()
|
||||
form.email.data = user.email
|
||||
form.name.data = user.firstname + (' ' if user.firstname and user.surname else '') + user.surname
|
||||
model = Model_View_Contact(form)
|
||||
html_body = render_template('pages/core/_contact.html', model = model)
|
||||
except Exception as e:
|
||||
Binary file not shown.
Binary file not shown.
BIN
controllers/store/__pycache__/stock_item.cpython-312.pyc
Normal file
BIN
controllers/store/__pycache__/stock_item.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
@@ -64,7 +64,7 @@ def filter_category():
|
||||
form_filters = Filters_Product_Category.from_json(data)
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'Form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
# ToDo: manually validate category, product
|
||||
@@ -76,7 +76,7 @@ def filter_category():
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
@@ -87,7 +87,7 @@ def save_category():
|
||||
form_filters = Filters_Product_Category.from_json(data[Model_View_Store_Product_Category.FLAG_FORM_FILTERS])
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
# filters_form = Filters_Product_Category.from_form(form_filters)
|
||||
@@ -95,7 +95,7 @@ def save_category():
|
||||
categories = data[Model_View_Store_Product_Category.FLAG_PRODUCT_CATEGORY]
|
||||
if len(categories) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'No categories.'
|
||||
})
|
||||
objsCategory = []
|
||||
@@ -113,7 +113,7 @@ def save_category():
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
159
controllers/store/product_permutation.py
Normal file
159
controllers/store/product_permutation.py
Normal file
@@ -0,0 +1,159 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Product Permutation Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
|
||||
# internal
|
||||
from business_objects.store.product import Filters_Product, Product_Permutation
|
||||
from forms.store.product_permutation import Filters_Product_Permutation
|
||||
from models.model_view_base import Model_View_Base
|
||||
from models.model_view_store import Model_View_Store
|
||||
from models.model_view_store_product_permutation import Model_View_Store_Product_Permutation
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
|
||||
|
||||
routes_store_product_permutation = Blueprint('routes_store_product_permutation', __name__)
|
||||
"""
|
||||
|
||||
@routes_store_product_permutation.route('/store/permutations', methods=['GET'])
|
||||
def permutation():
|
||||
filters = Filters_Product.get_default()
|
||||
model = Model_View_Store_Product_Permutation(filters_product=filters)
|
||||
return render_template('pages/store/_product_permutations.html', model = model)
|
||||
|
||||
@routes_store_product_permutation.route('/store/permutation_filter', methods=['POST'])
|
||||
def permutation_filter():
|
||||
data = Helper_App.get_request_data(request)
|
||||
form_filters = None
|
||||
try:
|
||||
form_filters = get_Form_Filters_Permutation(data)
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_FAILURE, Model_View_Base.FLAG_MESSAGE: f'Form invalid.\n{form_filters.errors}'})
|
||||
# ToDo: manually validate category, product
|
||||
filters_form = Filters_Product.from_form(form_filters)
|
||||
model = Model_View_Store_Product_Permutation(filters_product=filters_form)
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_SUCCESS, 'Success': True, Model_View_Base.KEY_DATA: model.category_list.to_permutation_row_list()})
|
||||
except Exception as e:
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_FAILURE, Model_View_Base.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'})
|
||||
|
||||
def get_Form_Filters_Permutation(data_request):
|
||||
data_form = data_request[Model_View_Store_Product_Permutation.KEY_FORM]
|
||||
form_filters = Filters_Product_Permutation(**data_form)
|
||||
form_filters.is_out_of_stock.data = av.input_bool(data_form['is_out_of_stock'], 'is_out_of_stock', 'permutations_post')
|
||||
return form_filters
|
||||
|
||||
@routes_store_product_permutation.route('/store/permutation_save', methods=['POST'])
|
||||
def permutation_save():
|
||||
data = Helper_App.get_request_data(request)
|
||||
form_filters = None
|
||||
try:
|
||||
form_filters = get_Form_Filters_Permutation(data)
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_FAILURE, Model_View_Base.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'})
|
||||
|
||||
permutations = data[Model_View_Store_Product_Permutation.FLAG_PRODUCT_PERMUTATION]
|
||||
if len(permutations) == 0:
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_FAILURE, Model_View_Base.FLAG_MESSAGE: f'No permutations.'})
|
||||
objsPermutation = []
|
||||
for permutation in permutations:
|
||||
objsPermutation.append(Product_Permutation.from_json(permutation))
|
||||
|
||||
# ToDo: manually validate category, product
|
||||
filters_form = Filters_Product.from_form(form_filters)
|
||||
model_save = Model_View_Store_Product_Permutation(filters_product=filters_form)
|
||||
model_save.save_permutations(data.comment, objsPermutation)
|
||||
|
||||
model_return = Model_View_Store_Product_Permutation(filters_product=filters_form)
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_SUCCESS, 'Success': True, Model_View_Base.KEY_DATA: model_return.category_list.to_permutation_row_list()})
|
||||
except Exception as e:
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_FAILURE, Model_View_Base.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'})
|
||||
"""
|
||||
|
||||
|
||||
@routes_store_product_permutation.route(Model_View_Store_Product_Permutation.HASH_PAGE_STORE_PRODUCT_PERMUTATIONS, methods=['GET'])
|
||||
def permutations():
|
||||
print('permutations')
|
||||
try:
|
||||
form_filters = Filters_Product_Permutation.from_json(request.args)
|
||||
except Exception as e:
|
||||
print(f'Error: {e}')
|
||||
form_filters = Filters_Product_Permutation()
|
||||
print(f'form_filters={form_filters}')
|
||||
model = Model_View_Store_Product_Permutation(form_filters)
|
||||
return render_template('pages/store/_product_permutations.html', model = model)
|
||||
|
||||
@routes_store_product_permutation.route(Model_View_Store_Product_Permutation.HASH_GET_STORE_PRODUCT_PERMUTATION, methods=['POST'])
|
||||
def filter_permutation():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Product_Permutation.from_json(data)
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Permutation.FLAG_MESSAGE: f'Form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
model = Model_View_Store_Product_Permutation(form_filters = form_filters)
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Permutation.KEY_DATA: model.category_list.to_json()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Permutation.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
@routes_store_product_permutation.route(Model_View_Store_Product_Permutation.HASH_SAVE_STORE_PRODUCT_PERMUTATION, methods=['POST'])
|
||||
def save_permutation():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Product_Permutation.from_json(data[Model_View_Store_Product_Permutation.FLAG_FORM_FILTERS])
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Permutation.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
# filters_form = Filters_Product_Permutation.from_form(form_filters)
|
||||
print(f'form_filters: {form_filters}')
|
||||
|
||||
permutations = data[Model_View_Store_Product_Permutation.FLAG_PRODUCT_PERMUTATION]
|
||||
if len(permutations) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Permutation.FLAG_MESSAGE: f'No permutations.'
|
||||
})
|
||||
objsPermutation = []
|
||||
for permutation in permutations:
|
||||
objsPermutation.append(Product_Permutation.from_json(permutation))
|
||||
# model_save = Model_View_Store_Product_Permutation() # filters_product=filters_form)
|
||||
print(f'objsPermutation={objsPermutation}')
|
||||
Model_View_Store_Product_Permutation.save_permutations(data.get('comment', 'No comment'), objsPermutation)
|
||||
|
||||
model_return = Model_View_Store_Product_Permutation(form_filters=form_filters)
|
||||
print('nips')
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Permutation.KEY_DATA: model_return.category_list.to_json()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Permutation.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ Initializes the Flask application, sets the configuration based on the environme
|
||||
# internal
|
||||
from business_objects.store.product import Product, Filters_Product, Product_Permutation
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from forms.forms import Form_Supplier, Form_Filters_Permutation, Form_Filters_Stock_Item
|
||||
from forms.forms import Form_Filters_Stock_Item
|
||||
from models.model_view_base import Model_View_Base
|
||||
from models.model_view_store import Model_View_Store
|
||||
from models.model_view_store_supplier import Model_View_Store_Supplier
|
||||
@@ -14,7 +14,7 @@ Initializes the Flask application, sets the configuration based on the environme
|
||||
# internal
|
||||
from business_objects.store.product import Product, Filters_Product, Product_Permutation
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from forms.forms import Form_Supplier, Form_Filters_Permutation, Form_Filters_Stock_Item
|
||||
from forms.forms import Form_Supplier, Form_Filters_Stock_Item
|
||||
from models.model_view_base import Model_View_Base
|
||||
from models.model_view_store import Model_View_Store
|
||||
from models.model_view_store_supplier import Model_View_Store_Supplier
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,8 @@ Datastore for Store
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.access_level import Access_Level, Filters_Access_Level
|
||||
from business_objects.store.access_level import Access_Level
|
||||
"""
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category
|
||||
from business_objects.store.currency import Currency
|
||||
@@ -23,13 +24,17 @@ from business_objects.store.delivery_region import Delivery_Region
|
||||
from business_objects.store.discount import Discount
|
||||
from business_objects.store.order import Order
|
||||
from business_objects.store.product import Product, Product_Permutation, Product_Price, Filters_Product # Permutation_Variation_Link
|
||||
"""
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.unit_measurement import Unit_Measurement
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
# from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_Container
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
from forms.access_level import Filters_Access_Level
|
||||
from forms.unit_measurement import Filters_Unit_Measurement
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
@@ -105,8 +110,8 @@ class DataStore_Base(BaseModel):
|
||||
while cursor.nextset():
|
||||
print(f'new result set: {cursor.fetchall()}')
|
||||
@classmethod
|
||||
def get_regions_and_currencies(cls):
|
||||
_m = 'DataStore_Base.get_regions_and_currencies'
|
||||
def get_many_region_and_currency(cls):
|
||||
_m = 'DataStore_Base.get_many_region_and_currency'
|
||||
_m_db_currency = 'p_shop_get_many_currency'
|
||||
_m_db_region = 'p_shop_get_many_region'
|
||||
|
||||
@@ -168,20 +173,45 @@ class DataStore_Base(BaseModel):
|
||||
def upload_bulk(permanent_table_name, records, batch_size):
|
||||
_m = 'DataStore_Base.upload_bulk'
|
||||
print(f'{_m}\nstarting...')
|
||||
print(f'permanent_table_name: {permanent_table_name}')
|
||||
if db.session.dirty or db.session.new or db.session.deleted:
|
||||
print("Session is not clean")
|
||||
return
|
||||
# Assuming `permanent_table_name` is a string representing the table name
|
||||
table_object = db.metadata.tables.get(permanent_table_name)
|
||||
if table_object is None:
|
||||
print(f"Table {permanent_table_name} not found in metadata.")
|
||||
return
|
||||
else:
|
||||
expected_columns = set(column.name for column in db.inspect(table_object).columns)
|
||||
print(f'expected_columns: {expected_columns}')
|
||||
|
||||
try:
|
||||
for i in range(0, len(records), batch_size):
|
||||
batch = records[i:i+batch_size]
|
||||
print(f'batch: {batch}')
|
||||
db.session.bulk_save_objects(batch)
|
||||
"""
|
||||
data = [object.to_json() for object in batch]
|
||||
print(f'batch: {batch}\ndata: {data}')
|
||||
db.session.bulk_insert_mappings(permanent_table_name, data)
|
||||
print(f'data: {data}')
|
||||
for row in data:
|
||||
row_keys = set(row.keys())
|
||||
if row_keys != expected_columns:
|
||||
print(f"Column mismatch in row: {row}")
|
||||
print(f'missing columns: {expected_columns - row_keys}')
|
||||
print(f'extra columns: {row_keys - expected_columns}')
|
||||
# db.session.bulk_insert_mappings(permanent_table_name, data)
|
||||
"""
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
print(f'{_m}\n{e}')
|
||||
db.session.rollback()
|
||||
raise e
|
||||
@classmethod
|
||||
def get_many_access_level(cls, filters):
|
||||
def get_many_access_level(cls, filters=None):
|
||||
_m = 'DataStore_Store_Base.get_many_access_level'
|
||||
if filters is None:
|
||||
filters = Filters_Access_Level()
|
||||
av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
||||
argument_dict = filters.to_json()
|
||||
# user = cls.get_user_session()
|
||||
@@ -213,4 +243,41 @@ class DataStore_Base(BaseModel):
|
||||
DataStore_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return access_levels, errors
|
||||
return access_levels, errors
|
||||
@classmethod
|
||||
def get_many_unit_measurement(cls, filters=None):
|
||||
_m = 'DataStore_Store_Base.get_many_unit_measurement'
|
||||
if filters is None:
|
||||
filters = Filters_Unit_Measurement()
|
||||
av.val_instance(filters, 'filters', _m, Filters_Unit_Measurement)
|
||||
argument_dict = filters.to_json()
|
||||
# user = cls.get_user_session()
|
||||
# argument_dict['a_id_user'] = 1 # 'auth0|6582b95c895d09a70ba10fef' # id_user
|
||||
print(f'argument_dict: {argument_dict}')
|
||||
print('executing p_shop_get_many_unit_measurement')
|
||||
result = cls.db_procedure_execute('p_shop_get_many_unit_measurement', argument_dict)
|
||||
cursor = result.cursor
|
||||
print('data received')
|
||||
|
||||
# units of measurement
|
||||
result_set_1 = cursor.fetchall()
|
||||
print(f'raw units of measurement: {result_set_1}')
|
||||
units = []
|
||||
for row in result_set_1:
|
||||
new_unit = Unit_Measurement.from_DB_unit_measurement(row)
|
||||
units.append(new_unit)
|
||||
|
||||
# Errors
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
print(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
||||
for error in errors:
|
||||
print(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return units, errors
|
||||
@@ -12,8 +12,6 @@ Datastore for Store
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
# from business_objects.store.access_level import Access_Level, Filters_Access_Level
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category
|
||||
from business_objects.store.currency import Currency
|
||||
@@ -26,11 +24,12 @@ from business_objects.store.product import Product, Product_Permutation, Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from business_objects.store.product_variation import Product_Variation_Type, Product_Variation, Product_Variation_Filters, Product_Variation_Container
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
import lib.argument_validation as av
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
@@ -118,12 +117,8 @@ class DataStore_Store_Base(DataStore_Base):
|
||||
# variations = [Product_Variation(**row) for row in result_set_4]
|
||||
variations = []
|
||||
for row in result_set_4:
|
||||
new_variation = Product_Variation.from_DB_get_many_product_catalogue(row) # (row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7])
|
||||
new_variation = Product_Variation.from_DB_get_many_product_catalogue(row)
|
||||
variations.append(new_variation)
|
||||
# products[product_index[new_variation.id_product]].variations.append(new_variation)
|
||||
# index_category = category_index[new_variation.id_category]
|
||||
# index_product = categories[index_category].index_product_from_ids_product_permutation(new_variation.id_product, new_variation.id_permutation)
|
||||
# categories[index_category].products[index_product].variations.append(new_variation)
|
||||
category_list.add_product_variation(new_variation)
|
||||
# print(f'variations: {variations}')
|
||||
# print(f'products: {[p.id_product for p in products]}')
|
||||
@@ -209,17 +204,13 @@ class DataStore_Store_Base(DataStore_Base):
|
||||
ids_permutation.append(msg_error_availability[:index_comma])
|
||||
return ids_permutation
|
||||
@classmethod
|
||||
def get_regions_and_currencies(cls):
|
||||
_m = 'DataStore_Store_Base.get_regions_and_currencies'
|
||||
def get_many_currency(cls):
|
||||
_m = 'DataStore_Store_Base.get_many_currency'
|
||||
_m_db_currency = 'p_shop_get_many_currency'
|
||||
_m_db_region = 'p_shop_get_many_region'
|
||||
|
||||
argument_dict_list_currency = {
|
||||
'a_get_inactive_currency': 0
|
||||
}
|
||||
argument_dict_list_region = {
|
||||
'a_get_inactive_currency': 0
|
||||
}
|
||||
|
||||
print(f'executing {_m_db_currency}')
|
||||
result = cls.db_procedure_execute(_m_db_currency, argument_dict_list_currency)
|
||||
@@ -235,6 +226,17 @@ class DataStore_Store_Base(DataStore_Base):
|
||||
print(f'currencies: {currencies}')
|
||||
DataStore_Store_Base.db_cursor_clear(cursor)
|
||||
|
||||
return currencies
|
||||
|
||||
@classmethod
|
||||
def get_many_region(cls):
|
||||
_m = 'DataStore_Store_Base.get_many_region'
|
||||
_m_db_region = 'p_shop_get_many_region'
|
||||
|
||||
argument_dict_list_region = {
|
||||
'a_get_inactive_currency': 0
|
||||
}
|
||||
|
||||
print(f'executing {_m_db_region}')
|
||||
result = cls.db_procedure_execute(_m_db_region, argument_dict_list_region)
|
||||
cursor = result.cursor
|
||||
@@ -250,7 +252,15 @@ class DataStore_Store_Base(DataStore_Base):
|
||||
DataStore_Store_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return regions
|
||||
|
||||
@classmethod
|
||||
def get_many_region_and_currency(cls):
|
||||
_m = 'DataStore_Store_Base.get_many_region_and_currency'
|
||||
currencies = cls.get_many_currency()
|
||||
regions = cls.get_many_region()
|
||||
return regions, currencies
|
||||
|
||||
@classmethod
|
||||
def get_many_product_variation(cls, variation_filters):
|
||||
_m = 'DataStore_Store_Base.get_many_product_variation'
|
||||
@@ -278,13 +288,30 @@ class DataStore_Store_Base(DataStore_Base):
|
||||
result = cls.db_procedure_execute('p_shop_get_many_product_variation', argument_dict_list)
|
||||
|
||||
cursor = result.cursor
|
||||
result_set = cursor.fetchall()
|
||||
result_set_vt = cursor.fetchall()
|
||||
|
||||
# Product_Variation Types
|
||||
# variation_container = Product_Variation_Container()
|
||||
variation_types = []
|
||||
variation_types_dict = {}
|
||||
for row in result_set_vt:
|
||||
new_variation_type = Product_Variation_Type.from_DB_get_many_product_variation(row)
|
||||
# variation_container.add_product_variation_type(new_variation_type)
|
||||
variation_types.append(new_variation_type)
|
||||
variation_types_dict[new_variation_type.id_type] = new_variation_type
|
||||
|
||||
print(f'variation_types_dict: {variation_types_dict}')
|
||||
|
||||
# Product_Variations
|
||||
variations = Product_Variation_List()
|
||||
for row in result_set:
|
||||
new_variation = Product_Variation.from_DB_variation(row)
|
||||
variations.add_product_variation(new_variation)
|
||||
cursor.nextset()
|
||||
result_set_v = cursor.fetchall()
|
||||
# variations = Product_Variation_Container()
|
||||
variations = []
|
||||
for row in result_set_v:
|
||||
new_variation = Product_Variation.from_DB_get_many_product_variation(row)
|
||||
new_variation.variation_type = variation_types_dict[new_variation.id_type]
|
||||
# variation_container.add_product_variation(new_variation)
|
||||
variations.append(new_variation)
|
||||
|
||||
errors = []
|
||||
cursor.nextset()
|
||||
@@ -299,5 +326,5 @@ class DataStore_Store_Base(DataStore_Base):
|
||||
|
||||
cursor.close()
|
||||
|
||||
return variations, errors
|
||||
return variation_types, variations, errors
|
||||
|
||||
@@ -25,7 +25,7 @@ from business_objects.store.product import Product, Product_Permutation, Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_Container
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
|
||||
@@ -24,7 +24,7 @@ from business_objects.store.product import Product, Product_Permutation, Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_Container
|
||||
# from datastores.datastore_base import Table_Shop_Product_Category, Table_Shop_Product_Category_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
@@ -83,7 +83,7 @@ class Row_Shop_Product_Temp(db.Model):
|
||||
'id_category': self.id_category,
|
||||
'name': self.name,
|
||||
'id_access_level_required': self.id_access_level_required,
|
||||
'active': self.active,
|
||||
'active': av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
'display_order': self.display_order,
|
||||
'guid': self.guid,
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ Datastore for Store Product Categories
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category, Product_Category_Temp
|
||||
from business_objects.store.currency import Currency
|
||||
from business_objects.store.image import Image
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
@@ -24,7 +24,7 @@ from business_objects.store.product import Product, Product_Permutation, Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_Container
|
||||
# from datastores.datastore_base import Table_Shop_Product_Category, Table_Shop_Product_Category_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
@@ -41,67 +41,6 @@ from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
# db = SQLAlchemy()
|
||||
|
||||
"""
|
||||
class Table_Shop_Product_Category(db.Model):
|
||||
__tablename__ = 'Shop_Product_Category'
|
||||
id_category: int = db.Column(db.Integer, primary_key=True)
|
||||
code: str = db.Column(db.String(50))
|
||||
name: str = db.Column(db.String(255))
|
||||
description: str = db.Column(db.String(4000))
|
||||
active: bool = db.Column(db.Boolean)
|
||||
display_order: int = db.Column(db.Integer)
|
||||
created_on: datetime = db.Column(db.DateTime)
|
||||
created_by: int = db.Column(db.Integer)
|
||||
id_change_set: int = db.Column(db.Integer)
|
||||
"""
|
||||
class Row_Shop_Product_Category_Temp(db.Model):
|
||||
__tablename__ = 'Shop_Product_Category_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_category: int = db.Column(db.Integer, primary_key=True)
|
||||
code: str = db.Column(db.String(50))
|
||||
name: str = db.Column(db.String(255))
|
||||
description: str = db.Column(db.String(4000))
|
||||
id_access_level_required: int = db.Column(db.Integer)
|
||||
active: bool = db.Column(db.Boolean)
|
||||
display_order: int = db.Column(db.Integer)
|
||||
guid: str = db.Column(db.BINARY(36))
|
||||
# created_on: datetime = db.Column(db.DateTime)
|
||||
# created_by: int = db.Column(db.Integer)
|
||||
|
||||
@classmethod
|
||||
def from_product_category(cls, product_category):
|
||||
row = cls()
|
||||
row.id_category = product_category.id_category[0] if isinstance(product_category.id_category, tuple) else product_category.id_category
|
||||
row.code = product_category.code[0] if isinstance(product_category.code, tuple) else product_category.code
|
||||
row.name = product_category.name[0] if isinstance(product_category.name, tuple) else product_category.name
|
||||
row.description = product_category.description[0] if isinstance(product_category.description, tuple) else product_category.description
|
||||
row.id_access_level_required = product_category.id_access_level_required[0] if isinstance(product_category.id_access_level_required, tuple) else product_category.id_access_level_required
|
||||
row.active = product_category.active
|
||||
row.display_order = product_category.display_order
|
||||
"""
|
||||
row.guid = product_category.guid
|
||||
row.created_on = product_category.created_on
|
||||
row.created_by = product_category.created_by
|
||||
"""
|
||||
return row
|
||||
def to_json(self):
|
||||
return {
|
||||
'id_category': self.id_category,
|
||||
'code': self.code,
|
||||
'name': self.name,
|
||||
'description': self.description,
|
||||
'id_access_level_required': self.id_access_level_required,
|
||||
'active': self.active,
|
||||
'display_order': self.display_order,
|
||||
'guid': self.guid,
|
||||
}
|
||||
"""
|
||||
'created_on': self.created_on,
|
||||
'created_by': self.created_by
|
||||
"""
|
||||
|
||||
|
||||
class DataStore_Store_Product_Category(DataStore_Store_Base):
|
||||
def __init__(self):
|
||||
@@ -120,8 +59,8 @@ class DataStore_Store_Product_Category(DataStore_Store_Base):
|
||||
rows = []
|
||||
id_category_new = 0
|
||||
for category in categories:
|
||||
# row = Row_Shop_Product_Category_Temp.from_product_category(category)
|
||||
row = category.to_temporary_record()
|
||||
row = Product_Category_Temp.from_product_category(category)
|
||||
# row = category.to_temporary_record()
|
||||
# id_tmp =
|
||||
if row.id_category == '':
|
||||
id_category_new -= 1
|
||||
@@ -147,7 +86,7 @@ class DataStore_Store_Product_Category(DataStore_Store_Base):
|
||||
cursor.close()
|
||||
print('cursor closed')
|
||||
"""
|
||||
DataStore_Store_Base.upload_bulk(rows, Product_Category.__tablename__, 1000)
|
||||
DataStore_Store_Base.upload_bulk(Product_Category_Temp.__tablename__, rows, 1000)
|
||||
|
||||
argument_dict_list = {
|
||||
'a_id_user': user.id_user,
|
||||
|
||||
@@ -12,21 +12,10 @@ Datastore for Store Product Permutations
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category
|
||||
from business_objects.store.currency import Currency
|
||||
from business_objects.store.image import Image
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.store.delivery_region import Delivery_Region
|
||||
from business_objects.store.discount import Discount
|
||||
from business_objects.store.order import Order
|
||||
from business_objects.store.product import Product, Product_Permutation, Product_Price, Filters_Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from business_objects.store.product_permutation import Product_Permutation, Product_Permutation_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
# external
|
||||
@@ -43,35 +32,72 @@ from datetime import datetime
|
||||
# db = SQLAlchemy()
|
||||
|
||||
|
||||
|
||||
class DataStore_Store_Product_Permutation(DataStore_Store_Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def save_permutations(self, comment, permutations):
|
||||
_m = 'DataStore_Store_Base.save_permutations'
|
||||
@classmethod
|
||||
def save_permutations(cls, comment, permutations):
|
||||
_m = 'DataStore_Store_Product_Permutation.save_permutations'
|
||||
av.val_str(comment, 'comment', _m)
|
||||
av.val_list(permutations, 'list_permutations', _m, Product_Permutation, 1)
|
||||
# av.val_list(permutations, 'list_permutations', _m, Product_Permutation, 1)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid()
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
now = datetime.now()
|
||||
user = self.get_user_session()
|
||||
user = cls.get_user_session()
|
||||
rows = []
|
||||
for permutation in permutations:
|
||||
setattr(permutation, 'guid', guid)
|
||||
setattr(permutation, 'created_on', now)
|
||||
setattr(permutation, 'created_by', user.id_user)
|
||||
# row = permutation.to_temporary_record()
|
||||
row = Product_Permutation_Temp.from_product_permutation(permutation)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
|
||||
cursor = self.db.cursor()
|
||||
print(f'rows: {rows}')
|
||||
|
||||
"""
|
||||
cursor = db.cursor()
|
||||
print('cursor created')
|
||||
cursor.executemany(
|
||||
'INSERT INTO Shop_Product_Permutation_Temp (id_permutation, id_product, description, cost_local, id_currency_cost, profit_local_min, latency_manufacture, quantity_min, quantity_max, quantity_step, quantity_stock, is_subscription, id_recurrence_interval, count_recurrence_interval, id_stripe_product, active, display_order, guid) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)',
|
||||
permutations
|
||||
'''INSERT INTO Shop_Product_Permutation_Temp (
|
||||
id_permutation,
|
||||
id_product,
|
||||
description,
|
||||
cost_local,
|
||||
id_currency_cost,
|
||||
profit_local_min,
|
||||
latency_manufacture_days,
|
||||
id_unit_measurement_quantity,
|
||||
count_unit_measurement_quantity,
|
||||
quantity_min,
|
||||
quantity_max,
|
||||
quantity_stock,
|
||||
is_subscription,
|
||||
id_unit_measurement_interval_recurrence,
|
||||
count_interval_recurrence,
|
||||
id_stripe_product,
|
||||
does_expire_faster_once_unsealed,
|
||||
id_unit_measurement_interval_expiration_unsealed,
|
||||
count_interval_expiration_unsealed,
|
||||
active,
|
||||
guid
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)''',
|
||||
rows
|
||||
)
|
||||
self.db.commit()
|
||||
|
||||
print('cursor executed')
|
||||
db.commit()
|
||||
print('cursor committed')
|
||||
cursor.close()
|
||||
print('cursor closed')
|
||||
"""
|
||||
DataStore_Store_Base.upload_bulk(Product_Permutation_Temp.__tablename__, rows, 1000)
|
||||
print('bulk uploaded')
|
||||
|
||||
argument_dict_list = {
|
||||
'a_id_user': user.id_user,
|
||||
'a_comment': comment,
|
||||
'a_guid': guid
|
||||
}
|
||||
self.db_procedure_execute('p_shop_save_permutation', argument_dict_list)
|
||||
|
||||
cursor.close()
|
||||
cls.db_procedure_execute('p_shop_save_product_permutation', argument_dict_list)
|
||||
print('saved product permutations')
|
||||
|
||||
@@ -25,7 +25,7 @@ from business_objects.store.product import Product, Product_Permutation, Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_Container
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
@@ -80,7 +80,7 @@ class DataStore_Store_Product_Variation(DataStore_Store_Base):
|
||||
result_set = cursor.fetchall()
|
||||
|
||||
# Product_Variations
|
||||
variations = Product_Variation_List()
|
||||
variations = Product_Variation_Container()
|
||||
for row in result_set:
|
||||
new_variation = Product_Variation.from_DB_variation(row)
|
||||
variations.add_product_variation(new_variation)
|
||||
|
||||
@@ -25,7 +25,7 @@ from business_objects.store.product import Product, Product_Permutation, Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_Container
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
|
||||
@@ -25,7 +25,7 @@ from business_objects.store.product import Product, Product_Permutation, Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_Container
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
|
||||
@@ -13,19 +13,9 @@ Datastore for Users
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category
|
||||
from business_objects.store.currency import Currency
|
||||
from business_objects.store.image import Image
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.store.delivery_region import Delivery_Region
|
||||
from business_objects.store.discount import Discount
|
||||
from business_objects.store.order import Order
|
||||
from business_objects.store.product import Product, Product_Permutation, Product_Price, Filters_Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Stock_Item_Filters
|
||||
from business_objects.user import User, User_Filters, User_Permission_Evaluation
|
||||
from business_objects.store.product_variation import Product_Variation, Product_Variation_Filters, Product_Variation_List
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
|
||||
BIN
forms/__pycache__/access_level.cpython-312.pyc
Normal file
BIN
forms/__pycache__/access_level.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
forms/__pycache__/unit_measurement.cpython-312.pyc
Normal file
BIN
forms/__pycache__/unit_measurement.cpython-312.pyc
Normal file
Binary file not shown.
37
forms/access_level.py
Normal file
37
forms/access_level.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Access Level Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling access level filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Access_Level(Form_Base):
|
||||
active = BooleanField("Active only?")
|
||||
def __repr__(self):
|
||||
return f'{self.__class__.__name__}(active={self.active.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
form = Filters_Access_Level()
|
||||
form.active.data = av.input_bool(json[Base.FLAG_ACTIVE], Base.FLAG_ACTIVE, f'{cls.__name__}.from_json')
|
||||
return form
|
||||
def to_json(self):
|
||||
return {
|
||||
Base.FLAG_ACTIVE: 1 if av.input_bool(self.active.data, Base.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json') else 0,
|
||||
}
|
||||
@@ -21,10 +21,12 @@ class Form_Base_Meta(type(FlaskForm), ABCMeta):
|
||||
|
||||
|
||||
class Form_Base(FlaskForm, metaclass=Form_Base_Meta):
|
||||
"""
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_filters(cls, filters):
|
||||
pass
|
||||
"""
|
||||
@abstractmethod
|
||||
def __repr__(self):
|
||||
pass
|
||||
@@ -43,4 +45,20 @@ class Form_Base(FlaskForm, metaclass=Form_Base_Meta):
|
||||
form_filters.is_not_empty.data = av.input_bool(data_form['is_not_empty'], 'is_not_empty', 'filter_category')
|
||||
form_filters.active.data = av.input_bool(data_form['active'], 'active', 'filter_category')
|
||||
return form_filters
|
||||
"""
|
||||
"""
|
||||
|
||||
'''
|
||||
class Filters_Stored_Procedure_Base(Form_Base):
|
||||
"""
|
||||
@abstractmethod
|
||||
def __repr__(self):
|
||||
pass
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
"""
|
||||
@abstractmethod
|
||||
def to_json(self):
|
||||
pass
|
||||
'''
|
||||
@@ -126,13 +126,6 @@ class Form_Supplier(FlaskForm):
|
||||
|
||||
# class Form_Supplier_Purchase_Order(FlaskForm):
|
||||
|
||||
class Form_Filters_Permutation(FlaskForm):
|
||||
id_category = SelectField('Category', validators=[Optional()], choices=[])
|
||||
id_product = SelectField('Product', validators=[Optional()], choices=[])
|
||||
is_out_of_stock = BooleanField('Out of stock only?')
|
||||
quantity_min = FloatField('Min stock')
|
||||
quantity_max = FloatField('Max stock')
|
||||
# submit = SubmitField('Submit')
|
||||
|
||||
class Form_Filters_Stock_Item(FlaskForm):
|
||||
id_category = SelectField('Category', validators=[Optional()], choices=[])
|
||||
|
||||
Binary file not shown.
BIN
forms/store/__pycache__/product_permutation.cpython-312.pyc
Normal file
BIN
forms/store/__pycache__/product_permutation.cpython-312.pyc
Normal file
Binary file not shown.
@@ -28,12 +28,14 @@ from abc import ABCMeta, abstractmethod
|
||||
class Filters_Product_Category(Form_Base):
|
||||
is_not_empty = BooleanField('Not empty only?')
|
||||
active = BooleanField("Active only?")
|
||||
"""
|
||||
@classmethod
|
||||
def from_filters(cls, filters):
|
||||
form = Filters_Product_Category()
|
||||
form.is_not_empty.data = filters.is_not_empty
|
||||
form.active.data = filters.active
|
||||
return form
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'Filters_Product_Category(is_not_empty={self.is_not_empty.data}, active={self.active.data})'
|
||||
@classmethod
|
||||
|
||||
65
forms/store/product_permutation.py
Normal file
65
forms/store/product_permutation.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Product Category Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling product category filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
# from business_objects.store.product_category import Filters_Product_Category
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
# from helpers.DEPRECATED.helper_abc import Interface_ABC
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Product_Permutation(Form_Base):
|
||||
id_category = SelectField('Category', validators=[Optional()], choices=[])
|
||||
id_product = SelectField('Product', validators=[Optional()], choices=[])
|
||||
is_out_of_stock = BooleanField('Out of stock only?')
|
||||
quantity_min = FloatField('Min stock')
|
||||
quantity_max = FloatField('Max stock')
|
||||
# submit = SubmitField('Submit')
|
||||
"""
|
||||
@classmethod
|
||||
def from_filters(cls, filters):
|
||||
form = Filters_Product_Permutation()
|
||||
form.id_category.choices = Store_Base.convert_list_objects_to_list_options(filters.categories)
|
||||
form.id_product.choices = Store_Base.convert_list_objects_to_list_options(filters.products)
|
||||
form.is_out_of_stock.data = filters.is_out_of_stock
|
||||
form.quantity_min.data = filters.quantity_min
|
||||
form.quantity_max.data = filters.quantity_max
|
||||
return form
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
Filters_Product_Permutation(
|
||||
id_category={self.id_category.data},
|
||||
id_product={self.id_product.data},
|
||||
is_out_of_stock={self.is_out_of_stock.data},
|
||||
quantity_min={self.quantity_min.data},
|
||||
quantity_max={self.quantity_max.data})
|
||||
'''
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
form = Filters_Product_Permutation()
|
||||
form.id_category.choices = [(json[Store_Base.ATTR_ID_PRODUCT_CATEGORY], json[Store_Base.ATTR_ID_PRODUCT_CATEGORY])]
|
||||
form.id_category.data = json[Store_Base.ATTR_ID_PRODUCT_CATEGORY]
|
||||
form.id_product.choices = [(json[Store_Base.ATTR_ID_PRODUCT], json[Store_Base.ATTR_ID_PRODUCT])]
|
||||
form.id_product.data = json[Store_Base.ATTR_ID_PRODUCT]
|
||||
form.is_out_of_stock.data = av.input_bool(json[Store_Base.FLAG_IS_OUT_OF_STOCK], 'is_out_of_stock', 'Filters_Product_Permutation')
|
||||
form.quantity_min.data = json[Store_Base.FLAG_QUANTITY_MIN]
|
||||
form.quantity_max.data = json[Store_Base.FLAG_QUANTITY_MAX]
|
||||
return form
|
||||
42
forms/unit_measurement.py
Normal file
42
forms/unit_measurement.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Unit of Measurement Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling unit of measurement filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Unit_Measurement(Form_Base):
|
||||
active = BooleanField("Active only?")
|
||||
@classmethod
|
||||
def from_filters(cls, filters):
|
||||
form = Filters_Unit_Measurement()
|
||||
form.active.data = filters.active
|
||||
return form
|
||||
def __repr__(self):
|
||||
return f'Filters_Unit_Measurement(active={self.active.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
form = Filters_Unit_Measurement()
|
||||
form.active.data = av.input_bool(json[Store_Base.FLAG_ACTIVE], 'active', 'Filters_Unit_Measurement')
|
||||
return form
|
||||
def to_json(self):
|
||||
return {
|
||||
Store_Base.FLAG_ACTIVE: av.input_bool(self.active.data, Store_Base.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user