236 Commits

Author SHA1 Message Date
f667d41c3c [HOTFIX] Fix broken link in supplier detail 2020-07-02 14:30:17 +02:00
3a85997f99 [HOTFIX] Fix broken link in supplier details 2020-07-02 14:26:37 +02:00
471d859987 [HOTFIX] Fix change password in intern 2020-07-02 00:50:20 +02:00
701e3c9cf6 remove sql debug output. Closes #125 2020-06-29 09:47:38 +02:00
e320f5b02b Merge pull request 'Cleanup. closes #75' (#131) from feature/rename into master
Reviewed-on: #131
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-26 10:09:39 +02:00
5aca84c43b delete old files. Cleanup repo 2020-06-26 10:06:41 +02:00
5b483d5c5d rename prototype folder -> web_backend. closes #75 2020-06-26 10:00:05 +02:00
037f1ff671 Merge pull request 'revisit ShoppingCart' (#130) from feature/revisit_shopping_cart into master
Reviewed-on: #130
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-26 09:52:11 +02:00
99896a4f77 revisit ShoppingCart 2020-06-25 16:52:13 +02:00
624ade2032 Merge pull request 'Set Default Payment on first order' (#128) from feature/update_credit_card_on_order into master
Reviewed-on: #128
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-25 12:40:19 +02:00
99b123565c Merge pull request 'Show all articles if no term is provided. fixes #127' (#129) from feature/fix_seatch_showing_err into master
Reviewed-on: #129
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-25 12:39:33 +02:00
be6de240bb fix encoding err in supplier cfg 2020-06-25 12:13:47 +02:00
7cf1819460 add session timeout 2020-06-25 12:10:38 +02:00
17f0c645f1 Show all articles if no term is provided. fixes #127 2020-06-25 11:52:27 +02:00
bdd1017232 Set Default Payment on first order 2020-06-25 11:46:01 +02:00
f4299c33c1 Merge pull request 'feature/email_validation_fe' (#126) from feature/email_validation_fe into master
Reviewed-on: #126
Reviewed-by: Lukas <lukas@xn--frderer-n2a.de>
2020-06-25 11:23:44 +02:00
f86a14b2f8 Fix Email pattern, disallow whitespace 2020-06-25 11:16:54 +02:00
2fb5826a3b Validate Email in FE 2020-06-25 11:10:20 +02:00
b993700ae4 Merge pull request 'feature/employee_login_defaults' (#124) from feature/employee_login_defaults into master
Reviewed-on: #124
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 19:00:36 +02:00
5d506a1526 Merge pull request 'Fix display order in various locations. closes #120' (#121) from feateure/display_order_intern into master
Reviewed-on: #121
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 18:59:14 +02:00
e87d0d8cdd Merge pull request 'feature/optimize_create_order_whbookings' (#117) from feature/optimize_create_order_whbookings into master
Reviewed-on: #117
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 18:57:45 +02:00
fb222c9213 Merge branch 'master' into feature/employee_login_defaults 2020-06-24 18:57:05 +02:00
cf9ab66e68 Hide /intern/ link if non employee. closes #76 2020-06-24 18:40:57 +02:00
cdc372d574 Redirect to intern if employee. 2020-06-24 18:40:22 +02:00
2290f01a8f Merge pull request 'feature/fix_delivery_api' (#116) from feature/fix_delivery_api into master
Reviewed-on: #116
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 18:38:03 +02:00
3bc0996c73 Merge pull request 'Add & generate tracking information to (Supplier-)OrderConfirmation. Fixes #110' (#114) from feature/supplier_tracking into master
Reviewed-on: #114
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 18:37:15 +02:00
758c6810ab Merge pull request 'Clean Shopping Cart on Logout' (#123) from feature/clean_shopping_on_logout into master
Reviewed-on: #123
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 18:27:24 +02:00
577a4f72f0 Clean Shopping Cart on Logout for real 2020-06-24 18:25:42 +02:00
a2aca7a8ca Clean Shopping Cart on Logout 2020-06-24 18:23:01 +02:00
3b7317a831 Fix typo 7 2020-06-24 18:19:14 +02:00
32921a3f87 Merge pull request 'Remove WarehouseBookingReason it was not used.' (#115) from feature/remove_unused_warehouse_booking_reason into master
Reviewed-on: #115
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 15:03:47 +02:00
63e9bc2336 Merge pull request 'Fix in stock calculation. closes #118' (#119) from feature/display_article_shop_in_stock into master
Reviewed-on: #119
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 15:03:04 +02:00
31bff55a20 Merge pull request 'Show advertisements distinct.' (#122) from feature/show_ads_distinct into master
Reviewed-on: #122
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-24 14:59:50 +02:00
5861b61565 Merge branch 'master' into feature/supplier_tracking 2020-06-24 10:44:38 +02:00
f0c9823e45 Clearify Inventory view with text. 2020-06-24 09:53:19 +02:00
6fbb16fea2 Show advertisements distinct. 2020-06-24 02:20:24 +02:00
0d547c8903 Fix display order in various locations. closes #120 2020-06-24 02:15:31 +02:00
5162e3fc19 Fix in stock calculation. closes #118 2020-06-24 02:05:25 +02:00
8bfe8b37f5 Maybe Fix warehouse booking repo 2020-06-24 02:00:37 +02:00
2e07d03908 Fix warehouse bookings on CreateOrderAction 2020-06-24 01:48:33 +02:00
b9e87f5bd4 Add additional infos for order history in /user/... fixes #109 2020-06-24 01:19:37 +02:00
cd641d6cc4 Fix #113 by fixing initialization of RestServiceForDelivery. 2020-06-24 01:18:16 +02:00
4e9f7800be Remove WarehouseBookingReason it was not used. 2020-06-24 00:42:55 +02:00
8d27c486d5 Add & generate tracking information to (Supplier-)OrderConfirmation. Fixes #110 2020-06-24 00:37:58 +02:00
714ac4f1de Fix issues with class loading in Cronjobs 2020-06-24 00:35:18 +02:00
186db31b17 Merge pull request 'Fix showing CustomerOrder all CustomerOrders in my orders. fix displaying orders in random order' (#108) from feature/fix_show_orders into master
reviewed by Lukas
2020-06-21 22:22:53 +02:00
fb53c68be3 Merge pull request 'implement Config for Supplier and Delivery Service' (#107) from feature/reading_config into master
reviewed by Lukas
2020-06-21 22:22:43 +02:00
19cf6ccfc5 Merge pull request 'Implement Supplier AutoSupplierPayment. closes #100' (#105) from feature/supplier_auto_payment into master 2020-06-21 22:13:41 +02:00
7fafd14715 Fix variable name 2020-06-21 19:01:25 +02:00
d5181f149a Fix showing CustomerOrder all CustomerOrders in my orders. fix displaying orders in random order 2020-06-21 18:58:15 +02:00
a950ecb2b9 Make delivery/gradlew executable 2020-06-21 18:42:33 +02:00
f42a50d24d fix CustomerOrder find by order 2020-06-21 18:32:04 +02:00
33118ddb2f Mark lost delivery as delivered. #spaghetticode 2020-06-21 18:25:33 +02:00
a6a2adc7db implement Config for Supplier and Delivery Service 2020-06-21 16:49:35 +02:00
62df2346c3 fix template crashing when defaultAddr == null 2020-06-21 16:28:00 +02:00
c1a0ecdcf3 fix delivery server crashing when tracking id not found 2020-06-21 16:13:48 +02:00
a1abbf5329 Implement Supplier AutoSupplierPayment. closes #100 2020-06-21 15:50:27 +02:00
deaf283a98 remove db blob 2020-06-21 01:08:58 +02:00
ffe9af0633 Prevent duplicate Articles from ArticleOffer 2020-06-21 01:07:04 +02:00
2989b54593 Merge pull request 'fix_change_user_name' (#104) from fix_change_user_name into master 2020-06-21 00:15:57 +02:00
b846b919b7 code clean up 2020-06-21 00:14:00 +02:00
1f83a82f17 removed user.name and use user.defaultDeliveryAddress.name instead 2020-06-21 00:13:10 +02:00
cd1a8568e6 show only one entry per article suggestions fix #96 2020-06-21 00:06:15 +02:00
53cdb20091 Merge pull request 'Fix the warehouse diagrams on the dashboard' (#103) from fix/dashboard_warehouse_statistics into master 2020-06-21 00:02:50 +02:00
9389675b5c Do not show dupliactes in category search. fixes #85 2020-06-21 00:01:28 +02:00
97a7f3a8ad Fix the warehouse diagrams on the dashboard
- Show the correct utilization
- Display values as correct percentages

Closes #99
2020-06-20 23:54:33 +02:00
aa2f42a10a Add password restrictions fixes #91 2020-06-20 23:47:53 +02:00
f128a8b9ed Make reason for manuel booking required. fixes #90 2020-06-20 23:35:56 +02:00
ffea25c082 Merge pull request 'Fix bad query for article slot sum' (#102) from feature/89_fix_lagerstand into master 2020-06-20 23:30:12 +02:00
d77b8c046a Fix bad query for article slot sum 2020-06-20 23:24:06 +02:00
8fdfe9cc69 Catch failing delivery server 2020-06-20 22:51:18 +02:00
e5332a3348 Fix String -> UUIDs -> String in method causing crash 2020-06-20 22:25:52 +02:00
c3eaf5ac11 Remove unused db fields 2020-06-20 22:10:53 +02:00
fa75beb9c4 Fix 6284a4d7bf altering template 2020-06-20 22:09:25 +02:00
4bef17dc0a Merge pull request 'feature/dashboard' (#83) from feature/dashboard into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-19 14:12:44 +02:00
79e4986880 delete blank line 2020-06-19 14:11:32 +02:00
181a09e16b Merge pull request 'feature/config' (#78) from feature/config into master
Reviewed-by: CodeSteak <codesteak@shellf.art>
2020-06-18 14:09:46 +02:00
f4aae9c581 ignore config.yml 2020-06-18 14:07:59 +02:00
ea0c8c45d6 rename eCommerce_config.yml to config.yml
* if no config file is present, create a default config file
2020-06-18 14:04:54 +02:00
8416783e0a merged 2020-06-18 01:13:03 +02:00
bcbebe8e8d master merged into feature/customer_orders 2020-06-18 01:11:11 +02:00
a570696795 feature/customer_orders merged into master 2020-06-18 01:07:11 +02:00
187656814e String Error -> Enum ErrorHandling Logic removed from model class 2020-06-18 00:50:43 +02:00
8c0652b26b exit if the settings file has not been found
* use a final variable for the settings file name
2020-06-17 22:32:48 +02:00
ef07447abc fix json-file 2020-06-17 20:42:08 +02:00
bb7b35dc28 Increase the amount of commits 2020-06-17 19:00:49 +02:00
93cfbb4a27 Merge remote-tracking branch 'origin/master' 2020-06-17 18:59:10 +02:00
68cc35cec3 Fix typo 6 2020-06-17 18:57:42 +02:00
b2ee048f25 Fix typo 5 2020-06-17 18:57:23 +02:00
020a30474e Fix typo 4 2020-06-17 18:56:32 +02:00
4bfc8a2cc6 Fix typo 3 2020-06-17 18:56:02 +02:00
0ff873baaa Fix typo 2 2020-06-17 18:55:50 +02:00
1812c89994 Fix typo 2020-06-17 18:55:29 +02:00
2442a477c8 add missing "|" 2020-06-17 18:43:06 +02:00
ebb3c8c235 removes unused Imports and fomattet 2020-06-17 17:23:29 +02:00
e6c068e71a Secretly fix number 0 showing on 'Warenkorb' 2020-06-17 00:23:05 +02:00
86e3ced19b Secretly fix searchbar not showing term when searching 2020-06-17 00:17:50 +02:00
44df9e4b4f Secretly add Favicon 2020-06-17 00:11:55 +02:00
18cbfbf148 Fix template strings with a starting "/" 2020-06-17 00:02:46 +02:00
e037b75f7c Merge pull request 'fix creditcard num not being set leading to crash' (#82) from feature/80_fix_creditcardnum_null_usersettings into master 2020-06-16 23:51:25 +02:00
486f237135 fix creditcard num not being set leading to crash 2020-06-16 23:50:10 +02:00
396d3fda14 Merge pull request 'Fix not creating directory when uploading file' (#80) from feature/fix_uploading_images into master 2020-06-16 23:40:12 +02:00
3b1d378968 Fix not creating directory when uploading file 2020-06-16 23:38:35 +02:00
5a0b303601 Merge branch 'master' into feature/config 2020-06-16 20:44:10 +02:00
d5825ba7a0 use @Autowired to get AppSettings Object 2020-06-16 20:42:40 +02:00
8199bd8a23 Merge pull request 'Allow employees to trigger cronjobs manually' (#74) from feature/manual_cronjobs into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-16 19:29:38 +02:00
774e62f892 add suppliers to YAMLData, store data in AppSettings() 2020-06-16 19:19:58 +02:00
e1c00eca8f fix ApplicationSettings.readConfig() 2020-06-16 18:52:33 +02:00
e904eba7a4 Merge remote-tracking branch 'origin/feature/manual_cronjobs' into feature/dashboard
Butfixes
2020-06-15 21:41:54 +02:00
6284a4d7bf Dashboard working 2020-06-15 17:47:55 +02:00
3b364ae815 Allow employees to trigger cronjobs manually 2020-06-15 16:23:42 +02:00
2ba4968556 Merge pull request 'feature/create_admin' (#73) from feature/create_admin into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-15 11:18:59 +02:00
18f35c43e7 remove spaces 2020-06-15 10:46:04 +02:00
709c80fa37 add fist admin user after start 2020-06-15 10:43:16 +02:00
87bade71b4 Dateien hochladen nach „supplier/config“ 2020-06-15 10:20:40 +02:00
b6eb66e348 Dateien hochladen nach „supplier/config“ 2020-06-15 10:19:16 +02:00
0a7722d612 removed register user type and ad 2020-06-15 09:40:32 +02:00
d121532fba Merge remote-tracking branch 'origin/master' into feature/config 2020-06-14 21:15:37 +02:00
985169117d fix nullpointer in settings 2020-06-14 18:19:59 +02:00
fa610cae3b if no orders show hint 2020-06-14 17:56:09 +02:00
3bb3c5b513 [HOTFIX] of HOTFIX: Use CanonicalPath for check 2020-06-14 16:51:59 +02:00
15616e05f3 [HOTFIX] Prevent path directory traversal attack for deploy 2020-06-14 15:54:56 +02:00
0ab185f143 impl trackingID for the UserController 2020-06-13 21:59:18 +02:00
1dd4b5cfa5 del update query and impl error for trackigID 2020-06-13 20:05:22 +02:00
266bba095a merged feature/customer_orders with master 2020-06-13 19:58:30 +02:00
fa7bdf2f7e impl error handling 2020-06-13 19:37:34 +02:00
76550be9e7 Merge pull request 'Allow partial discount on supplier orders' (#68) from fix/discount_calculation_in_supplier_service into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-13 12:21:26 +02:00
ef8aa826a3 Merge pull request 'Fix the cash booking sum on customer order' (#67) from fix/wrong_bookings_on_customer_order into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-13 12:19:18 +02:00
114453b5b9 Merge pull request 'Implement Arrival of Supplier Order.' (#62) from feature/supplier_order_arrived_button into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-13 11:59:17 +02:00
7397698929 fix check for missing article 2020-06-13 11:54:25 +02:00
9fa2c1f3a7 Allow partial discount on supplier orders
Closes #46
2020-06-13 11:46:16 +02:00
327ba182f5 Fix the cash booking sum on customer order
Closes #57
2020-06-13 11:10:20 +02:00
30226c5c19 Merge pull request 'fixes_ui' (#66) from fixes_ui into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-13 11:03:20 +02:00
e0e853a575 fixes from PR review 2020-06-13 10:41:59 +02:00
d2b98f083b Merge pull request 'fix missing cells in TODO-Warehouse. fixes #63' (#64) from feature/63_fix_todo_ui into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-13 10:26:36 +02:00
a41889b2cb login in extern loginController, RequestController cleanup, login right after register 2020-06-12 23:48:28 +02:00
0f7d248d40 add radio BTNs to register 2020-06-12 23:31:57 +02:00
11ade7b8f9 fix missing cells in TODO-Warehouse. fixes #63 2020-06-12 19:57:50 +02:00
a664b42853 Allow reuse of empty warehouse slots. Also fixes #59 2020-06-12 19:48:21 +02:00
56f4ec0dda Implement Arrival of Supplier Order. 2020-06-12 19:22:36 +02:00
1590821f64 delete bonuspoints and notifications html 2020-06-12 11:15:05 +02:00
16803d2b12 Merge pull request 'feature/customers' (#58) from feature/customers into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-12 00:52:53 +02:00
938d16301d fix stuff 2020-06-10 20:10:12 +02:00
5a59ac11b0 code cleanup 2020-06-10 19:28:12 +02:00
c194f44308 implement customers detail bookings 2020-06-10 19:28:12 +02:00
fc68e231d3 Allow the user to create manual bookings 2020-06-10 19:28:07 +02:00
6d8a36b7ac implement customers detail part 2 2020-06-10 19:27:38 +02:00
49e26039a3 implement customers detail part 1 2020-06-10 19:27:38 +02:00
28834431ce Display financial bookings in the ui 2020-06-10 19:27:38 +02:00
5691f0eeec implement customers index 2020-06-10 19:27:16 +02:00
7f643987f3 fix wrong closing tags in customerOrder/id.html 2020-06-10 19:12:34 +02:00
6b8bf25e0e Merge pull request 'feature/cash_bookings' (#55) from feature/cash_bookings into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-10 19:04:45 +02:00
ebeba72278 impl tracking ID 2020-06-10 17:03:59 +02:00
f671baf7f0 Error with package path 2020-06-10 14:51:12 +02:00
691916894f Apply some changes according to comments on the pullrequest 2020-06-10 11:48:38 +02:00
e7e2017825 Merge pull request 'Show a hyphen in supplier column if an article is not offered by anyone' (#56) from fix/null_pointer_deref_in_SupplierOfferController into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-09 14:06:51 +02:00
03d557d67b Show a hyphen in supplier column if an article is not offered by anyone
Closes #54
2020-06-08 18:56:35 +02:00
8fff0e2dca Merge remote-tracking branch 'origin/master' into feature/cash_bookings 2020-06-08 18:15:34 +02:00
6317780dfa Merge pull request 'Implement Warehouse....' (#47) from feature/intern_warehouse into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-08 13:40:10 +02:00
78a7ad053a Merge branch 'master' into feature/intern_warehouse 2020-06-08 09:22:06 +02:00
f6554629d7 Merge branch 'master' into feature/intern_warehouse 2020-06-08 09:14:50 +02:00
eb82d05f4f Use Spring model for template attributes 2020-06-08 09:14:11 +02:00
41320473d9 Merge pull request 'feature/supplier_page' (#52) from feature/supplier_page into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-07 15:00:56 +02:00
bd6be54149 removed space in SupplierOrderRepo 2020-06-07 11:45:53 +02:00
99612165f5 fixed review requests 2020-06-07 11:44:50 +02:00
9dff6adb3d rebase to master 2020-06-05 21:25:38 +02:00
445b504188 code cleanup 2020-06-05 21:20:54 +02:00
bd8b3db7f3 added post form for marking order as delivered 2020-06-05 21:18:04 +02:00
8a4ff4cfa5 added supplier bookings table 2020-06-05 21:18:04 +02:00
2245309198 added supplier balance label 2020-06-05 21:18:04 +02:00
d078c44027 finished supplier orders 2020-06-05 21:18:04 +02:00
bd8b07990b finished show orders based on supplier 2020-06-05 21:18:04 +02:00
2f4c45ed71 show orders based on supplier 2020-06-05 21:18:04 +02:00
b600040bf3 basic detail page for supplier 2020-06-05 21:18:04 +02:00
4f5e1fe185 list suppliers page 2020-06-05 21:18:04 +02:00
f348d33c94 Show the balances of the main and vat account in the dashboard 2020-06-05 19:17:44 +02:00
6f90b9c941 Fix a bug where bookings were invisible if they affected only one account 2020-06-05 18:58:16 +02:00
e53c1e0872 Allow the user to create manual bookings 2020-06-05 18:45:25 +02:00
7f652e38f0 fix nullpointer in category search 2020-06-05 12:32:34 +02:00
0061d25082 Display financial bookings in the ui 2020-06-05 07:49:11 +02:00
d4ddd8a9a3 Merge pull request 'feature/user' (#38) from feature/user into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-03 18:36:06 +02:00
a192f0ac51 Set Tracing Id in Warehouse/finish not in Checkout. This was wrong. 2020-06-03 16:55:36 +02:00
9660e52f34 Merge pull request 'feature/31_js_magic_article_edit' (#50) from feature/31_js_magic_article_edit into master 2020-06-02 07:47:28 +02:00
72ddfa42ef Merge pull request 'Show Tax in Article Edit View. Fixes #48' (#49) from feature/48_not_showing_tax_edit_view into master 2020-06-02 07:47:04 +02:00
fc239983a7 Fix article links. 2020-06-01 21:15:27 +02:00
5e1170839e Update Gross Price in Article Edit View. Fixes #31 2020-06-01 21:11:15 +02:00
2ef9eb29ac Show Tax in Article Edit View. Fixes #48 2020-06-01 20:46:00 +02:00
f4ba79a4cd add id's to form inputs 2020-06-01 20:27:19 +02:00
976e2d1949 Implement Warehouse....
Sry, only one commit. No time to make history ;D
2020-06-01 20:25:51 +02:00
b7134a60da rename CustomerOrderRepo in Cronjob 2020-06-01 20:25:31 +02:00
ff4c984f54 fix error message 2020-06-01 20:24:45 +02:00
21502a0b1c Merge branch 'master' into feature/user 2020-06-01 19:03:42 +02:00
b38ffdea34 Merge pull request 'feature/offered_article_supplier' (#40) from feature/offered_article_supplier into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-01 17:10:21 +02:00
6988d3f213 minor code clean up 2020-06-01 17:10:04 +02:00
f5ad05f49f Merge branch 'master' into feature/offered_article_supplier 2020-06-01 17:04:52 +02:00
e539a9433a Merge pull request 'implement better search' (#43) from feature/search into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-01 16:59:37 +02:00
b14c565e81 Merge pull request 'Store the cheapest supplier for each offered article in the database' (#41) from feature/reorder_cronjob into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-01 16:53:58 +02:00
b04d627695 Merge pull request 'check if article.image is null' (#44) from fix/image_null into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
2020-06-01 16:51:23 +02:00
839bebcd89 trim searchterm 2020-06-01 11:58:08 +02:00
3775f96f3f implement getCustomerOrderDetail 2020-06-01 11:53:29 +02:00
2394157be8 implement getCustomerOrder 2020-06-01 11:31:12 +02:00
922e3cadef Bugfix register 2020-06-01 11:13:03 +02:00
0fb1d5704e Bufix: After register, you now logged in 2020-06-01 11:11:34 +02:00
dfa528484c Merge branch 'master' into feature/user 2020-06-01 10:57:55 +02:00
38fcda708f check if article.image is null 2020-06-01 10:53:10 +02:00
9238162a4c implement better search 2020-06-01 10:52:19 +02:00
e7e3864b4c Store the cheapest supplier for each offered article in the database 2020-05-30 18:25:23 +02:00
407229f15d changed cheapest supplier ref in offered article entity 2020-05-30 16:49:20 +02:00
8a2eff1fe9 code cleanup 2020-05-27 19:03:18 +02:00
e4d6642d61 order orders by newest first 2020-05-27 15:52:51 +02:00
9406bbc4ac fix nullpointer again 2020-05-27 15:10:12 +02:00
e5b28250c2 fix payment method null pointer 2020-05-27 14:56:15 +02:00
db1d3d31b2 fix register 2020-05-27 14:55:51 +02:00
819cca7f2a Merge remote-tracking branch 'origin/feature/user' into feature/user 2020-05-27 13:41:04 +02:00
846e448f01 code cleanup 2020-05-27 13:40:44 +02:00
614a929592 code cleanup 2020-05-27 13:40:44 +02:00
60699ed847 fix error handling 2020-05-27 13:40:44 +02:00
83ad1f3999 remove advertisementflag 2020-05-27 13:40:44 +02:00
5b4c0be1c8 add Errorhandling to UpdateSettingsAction 2020-05-27 13:40:44 +02:00
0256c19e8f implement change User Settings 2020-05-27 13:40:44 +02:00
adcd840154 remove notification center 2020-05-27 13:40:44 +02:00
b5495bda3d show all Orders 2020-05-27 13:40:44 +02:00
106b00a907 show usersettings from db 2020-05-27 13:40:44 +02:00
7c73f69865 remove bonuspoints 2020-05-27 13:40:44 +02:00
86a2e5d8c2 code cleanup 2020-05-25 12:17:09 +02:00
8d65998ac2 code cleanup 2020-05-25 10:21:36 +02:00
178f98d664 fix error handling 2020-05-25 10:10:42 +02:00
33ff754b9d remove advertisementflag 2020-05-25 09:36:40 +02:00
8ede86fdce add Errorhandling to UpdateSettingsAction 2020-05-20 12:08:57 +02:00
39eefbdd3e implement change User Settings 2020-05-19 15:18:48 +02:00
6e3d1cbcf5 remove notification center 2020-05-19 14:17:38 +02:00
1ce9a971ba show all Orders 2020-05-19 11:52:41 +02:00
4711527971 show usersettings from db 2020-05-18 14:41:33 +02:00
b7b5c7a6b3 remove bonuspoints 2020-05-18 12:49:37 +02:00
bba4173269 fixed inputstream once more 2020-05-10 22:19:58 +02:00
e1d7becc2e added yaml dump&parse class 2020-05-10 21:23:44 +02:00
266 changed files with 5113 additions and 126637 deletions

0
delivery/gradlew vendored Normal file → Executable file
View File

View File

@ -4,9 +4,9 @@ package org.hso.ecommerce.supplier;
import org.hso.ecommerce.supplier.data.Delivery;
import org.hso.ecommerce.supplier.data.DeliveryManager;
import org.hso.ecommerce.supplier.data.ReturnStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -19,14 +19,19 @@ public class RequestController {
public String supplier(HttpServletResponse response, HttpServletRequest request, @RequestBody Delivery delivery) {
DeliveryManager.getInstance().add(delivery);
return delivery.getUuid().toString();
return delivery.getUuid();
}
@GetMapping("/status")
@GetMapping(value = "/status", produces = MediaType.APPLICATION_JSON_VALUE)
public ReturnStatus searchArticles(@RequestParam(value = "trackingID") String trackingID, HttpServletRequest request, HttpServletResponse response) {
Delivery delivery = DeliveryManager.getInstance().getDeliveryByeID(trackingID);
Delivery delivery = DeliveryManager.getInstance().getDeliveryByID(trackingID);
if (delivery == null) {
Delivery lostDelivery = Delivery.lostDelivery(trackingID);
DeliveryManager.getInstance().add(lostDelivery);
delivery = lostDelivery;
}
return new ReturnStatus(delivery.getStatus(),delivery.getEstimatedArrival());
return new ReturnStatus(delivery.getStatus(), delivery.getEstimatedArrival());
}
}

View File

@ -8,38 +8,48 @@ import java.util.UUID;
public class Delivery {
private String[] states = {"Bestellung eingegangen","Bestellung auf dem Weg","Lieferung erfolgreich"};
private int[] timeBorder = {4,24};
private String[] states = {"Bestellung eingegangen", "Bestellung auf dem Weg", "Lieferung erfolgreich"};
private int[] timeBorder = {4, 24};
private String name;
private String address;
private String estimatedArrival;
private Date creationTime;
private UUID uuid;
public Delivery(String name, String address)
{
// Why is this a string and creationTime a Date?!
private String estimatedArrival;
private Date creationTime;
private String uuid;
public Delivery(String name, String address) {
this.name = name;
this.address = address;
this.uuid = UUID.randomUUID();
this.uuid = UUID.randomUUID().toString();
this.creationTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
this.estimatedArrival = formatter.format(addDays((Date)this.creationTime.clone(),1));
this.estimatedArrival = formatter.format(addDays((Date) this.creationTime.clone(), 1));
}
public static Delivery lostDelivery(String uuid) {
Delivery delivery = new Delivery("", "");
delivery.uuid = uuid;
delivery.creationTime = addDays(new Date(), -1);
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
delivery.estimatedArrival = formatter.format(addDays((Date) delivery.creationTime.clone(), 1));
return delivery;
}
public String getStatus()
{
public String getStatus() {
Date now = new Date();
Long timeNow = now.getTime();
Long creationTime = this.creationTime.getTime();
long timeNow = now.getTime();
long creationTime = this.creationTime.getTime();
Long diff = timeNow - creationTime;
// Wow, that's how calculate date diffs.
long diff = timeNow - creationTime;
double hour = (((diff / 1000.0) / 3600.0));
for (int i = 0; i < timeBorder.length; i++) {
for (int i = 0; i < timeBorder.length; i++) {
if(hour < timeBorder[i])
if (hour < timeBorder[i])
return states[i];
}
@ -51,15 +61,14 @@ public class Delivery {
return estimatedArrival;
}
private Date addDays(Date date, int days)
{
private static Date addDays(Date date, int days) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.DATE, days);
return cal.getTime();
}
public UUID getUuid() {
public String getUuid() {
return uuid;
}

View File

@ -1,20 +1,18 @@
package org.hso.ecommerce.supplier.data;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.HashMap;
public class DeliveryManager {
private List<Delivery> deliveryList;
private HashMap<String, Delivery> deliveryList;
private static DeliveryManager deliveryManager;
private DeliveryManager()
{
deliveryList = new ArrayList<>();
deliveryList = new HashMap<>();
}
public static DeliveryManager getInstance () {
public static DeliveryManager getInstance() {
if (DeliveryManager.deliveryManager == null) {
DeliveryManager.deliveryManager = new DeliveryManager();
@ -22,13 +20,11 @@ public class DeliveryManager {
return DeliveryManager.deliveryManager;
}
public boolean add(Delivery delivery)
{
return deliveryList.add(delivery);
public void add(Delivery delivery) {
deliveryList.put(delivery.getUuid(), delivery);
}
public Delivery getDeliveryByeID(String uuid)
{
return deliveryList.parallelStream().filter(d -> d.getUuid().equals(UUID.fromString(uuid))).findAny().get();
public Delivery getDeliveryByID(String uuid) {
return deliveryList.getOrDefault(uuid, null);
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,479 +0,0 @@
:root {
font-family: "Fira Sans";
line-height: 1.15;
--u5: calc(1em * 1.5 * 1.5 * 1.5 * 1.5 * 1.5 );
--u4: calc(1em * 1.5 * 1.5 * 1.5 * 1.5);
--u3: calc(1em * 1.5 * 1.5 * 1.5);
--u2: calc(1em * 1.5 * 1.5);
--u1: calc(1em * 1.5);
--u0: calc(1em);
--u-1: calc(1em * 0.666);
--u-2: calc(1em * 0.666 * 0.666);
--u-3: calc(1em * 0.666 * 0.666 * 0.666);
--u-4: calc(1em * 0.666 * 0.666 * 0.666 * 0.666);
--root-c-base: #ecf0f1;
--root-c-base-highlight: #bdc3c7;
--root-c-primary: #1abc9c;
--root-c-primary-highlight: #16a085;
--root-c-secondary: #9b59b6;
--root-c-secondary-highlight: #8e44ad;
--root-c-black: #2c3e50;
--root-c-black-highlight: #34495e;
--c-base: var(--root-c-base);
--c-base-highlight: var(--root-c-base-highlight);
--c-primary:var(--root-c-primary);
--c-primary-highlight: var(--root-c-primary-highlight);
--c-secondary: var(--c-secondary);
--c-secondary-highlight: var(--root-c-secondary-highlight);
--c-black: var(--root-c-black);
--c-black-highlight: var(--root-c-black-highlight);
}
.primary {
--c-base: var(--root-c-base);
--c-base-highlight: var(--root-c-base-highlight);
--c-primary:var(--root-c-primary);
--c-primary-highlight: var(--root-c-primary-highlight);
--c-secondary: var(--c-secondary);
--c-secondary-highlight: var(--root-c-secondary-highlight);
--c-black: var(--root-c-black);
--c-black: var(--root-c-black-highlight);
}
.secondary {
--c-base: var(--root-c-base);
--c-base-highlight: var(--root-c-base-highlight);
--c-primary:var(--root-c-secondary);
--c-primary-highlight: var(--root-c-secondary-highlight);
--c-secondary: var(--root-c-primary);
--c-secondary-highlight: var(--root-c-primary-highlight);
--c-black: var(--root-c-black);
--c-black-highlight: var(--root-c-black-highlight);
}
.inverted {
--c-base: var(--root-c-black);
--c-base-highlight: var(--root-c-black-highlight);
--c-primary:var(--root-c-primary);
--c-primary-highlight: var(--root-c-primary-highlight);
--c-secondary: var(--c-secondary);
--c-secondary-highlight: var(--root-c-secondary-highlight);
--c-black: var(--root-c-base);
--c-black-highlight: var(--root-c-base-highlight);
}
* {
margin: 0em;
padding: 0em;
box-sizing: border-box;
}
html, body {
font-size: var(--u0);
height: 100%;
background-color: var(--c-base);
color: var(--c-black)
}
main {
min-height: 100%;
}
h1, h2, h3, h4, h5 {
font-family: "Fira Mono";
padding-top: 1em;
padding-bottom: 0.618em;
text-transform: uppercase;
}
p {
padding-top: 1em;
}
h1 {
font-size: var(--u2);
}
h2 {
font-size: var(--u1);
}
h3, h4, h5 {
font-size: var(--u0);
}
img {
width: 100%;
object-fit: cover;
}
li {
list-style-type: none;
}
table {
width: 100%;
border-collapse: collapse;
}
table td,
table th {
padding: var(--u0);
text-align: center;
}
table th {
background-color: var(--c-primary);
color: var(--c-base);
}
table tr:nth-child(2n+1) {
background-color: var(--c-base-highlight);
}
/*
* NAV
*/
nav {
}
nav h1 {
font-size: var(--u0);
margin: 0rem;
}
nav li {
display: flex;
flex-direction: column;
}
nav li li {
margin-left: var(--u0);
}
nav li a {
padding: var(--u0);
transition: all 0.1s ease-out;
}
nav li a:hover,
nav li a.selected {
padding: var(--u0);
background-color: var(--c-primary);
color: var(--c-base);
}
/*
* FOOTER
*/
footer {
padding-top: var(--u3);
padding-bottom: var(--u1);
}
/*
* INPUTS
*/
form * {
width: 100%;
}
input[type="text"],
input[type="password"] {
background-color: var(--c-base);
border: none;
border-radius: var(--u-2);
margin-top: var(--u0);
margin-bottom: var(--u0);
padding: var(--u0);
font-size: var(--u0);
color: var(--c-black);
/* box-shadow: var(--s-0-secondary); */
}
input[type="text"]::placeholder,
input[type="password"]::placeholder {
color: var(--c-primary-highlight);
opacity: 50%;
}
button, .button {
font-family: "Fira Mono";
font-weight: bold;
background-color: var(--c-primary);
color: var(--c-base);
border: none;
border-radius: var(--u-2);
margin-bottom: var(--u0);
margin-top: var(--u0);
padding: var(--u0);
min-width: 10em;
font-family: "Fira Mono";
text-transform: uppercase;
font-size: var(--u0);
/* box-shadow: var(--s-0-secondary); */
}
button:active, .button:active {
background-color: var(--c-primary-highlight);
}
input[type="text"],
input[type="password"],
button,
.button {
transition: all 0.1s ease-out;
}
label {
display: block;
min-width: 10em;
font-weight: bold;
}
/*
* HERO
*/
.hero {
background-color: var(--c-primary);
color: var(--c-base);
}
.hero-black {
background-color: var(--c-black);
color: var(--c-base);
}
/*
* LAYOUT
*/
.content-width {
max-width: 80rem;
margin-left: auto;
margin-right: auto;
padding-left: var(--u0);
padding-right: var(--u0);
}
.bar-flex {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
}
.bar-flex > * {
margin: var(--u0);
}
.bar-flex > .spacer {
flex: 1;
}
.sidebar-layout {
display: flex;
align-items: stretch;
justify-content: center;
flex-wrap: wrap;
}
.sidebar-layout > *:nth-child(2) {
flex: 1;
}
.grid {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
.grid.vertical-center {
align-items: center;
height: 100%;
}
.grid.center {
justify-content: space-around;
}
.grid > * {
flex: 1;
margin: var(--u0);
padding: var(--u0);
border-radius: var(--u0);
}
.grid.base > * {
background-color: var(--c-base);
color: var(--c-black);
}
.grid.black > * {
background-color: var(--c-black);
color: var(--c-base);
}
.grid.primary > * {
background-color: var(--c-primary);
color: var(--c-base);
}
.grid.secondary > * {
background-color: var(--c-primary-highlight);
color: var(--c-base);
}
.hero-primary .grid.shadow > * {
/* box-shadow: var(--s-0-secondary); */
}
.hero-black .grid.shadow > * {
/* box-shadow: var(--s-0-secondary); */
}
.grid.s > .spacer {
box-shadow: none;
margin: calc(var(--u0) * 2);
padding: 0px;
width: 10rem;
max-width: 10rem;
min-width: 7.5rem;
height: 0px;
}
.grid.s > * {
max-width: 10rem;
min-width: 7.5rem;
}
.grid.m > .spacer {
box-shadow: none;
margin: calc(var(--u0) * 2);
padding: 0px;
width: 20rem;
max-width: 20rem;
min-width: 15rem;
height: 0px;
padding: 0px;
}
.grid.m > * {
width: 20rem;
max-width: 20rem;
min-width: 15rem;
}
.grid.l > .spacer {
box-shadow: none;
margin: calc(var(--u0) * 2);
padding: 0px;
width: 40rem;
max-width: 40rem;
min-width: 15rem;
height: 0px;
padding: 0px;
}
.grid.l > * {
width: 40rem;
max-width: 40rem;
min-width: 15rem;
}
.vertical-spacer.s {
min-height: 10rem;
}
.vertical-spacer.m {
min-height: 20rem;
}
.vertical-spacer.l {
min-height: 40rem;
}
/*
* Impov
*/
.input-icon {
/* box-shadow: var(--s-0-secondary); */
display: flex;
padding: 0px;
border-radius: var(--u0);
}
.input-icon > input {
flex: 1;
margin: 0px;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
box-shadow: none;
}
.input-icon > button {
margin: 0px;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
box-shadow: none;
}
/*
* CONTENT
*/
.price {
opacity: 75%;
font-size: var(--u1);
text-align: right;
}

View File

@ -1,124 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr">
<head>
<meta charset="utf-8">
<title>Frontpage</title>
<link rel="stylesheet" type="text/css" href="css/ecom.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
</head>
<body>
<nav class='hero'>
<div class='content-width bar-flex'>
<h1>Project eCommerce</h1>
<button>Angebote</button>
<div class='spacer input-icon secondary'>
<input type="text" placeholder="Nach Produkten suchen..."/>
<button>Finden</button>
</div>
<button>Login</button>
</div>
</nav>
<main>
<div class='hero'>
<div class='content-width'>
<h1>Angebote</h1>
<div class='grid m base shadow'>
<section>
<img src="pics/product-1.jpg">
<h2>Lorem Ipsum</h2>
<p class='price'> 25.14 €</p>
<p>
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
</p>
</section>
<section>
<img src="pics/product-2.jpg">
<h2>Lorem Ipsum</h2>
<p class='price'> 10.14 €</p>
<p>
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
</p>
</section>
<section>
<img src="pics/product-1.jpg">
<h2>Lorem Ipsum</h2>
<p class='price'> 25.14 €</p>
<p>
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
</p>
</section>
<section>
<img src="pics/product-2.jpg">
<h2>Lorem Ipsum</h2>
<p class='price'> 10.14 €</p>
<p>
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
</p>
</section>
<section>
<img src="pics/product-3.jpg">
<h2>Lorem Ipsum</h2>
<p class='price'> 44.14 €</p>
<p>
Als Gregor Samsa eines Morgens aus unruhigen Träumen erwachte.
</p>
</section>
<section class="spacer"></section>
<section class="spacer"></section>
<section class="spacer"></section>
<section class="spacer"></section>
</div>
</div>
<div class="vertical-spacer s"></div>
</div>
<div class=''>
<div class='content-width'>
<h1>Personalisierte Empfehlungen</h1>
<div class="grid l">
<img src="undraw/undraw_successful_purchase_secondary.svg"/>
<div>
<h2>Werde jetzt Kunde</h2>
<p> Jetzt Kunde werden und viele Vorteile sichern,
wie z.B. personalisierte Empfehlungen. </p>
<button>Registieren</button>
</div>
</div>
</div>
<div class="vertical-spacer s"></div>
</div>
</main>
<footer class="hero-black">
<div class='content-width bar-flex'>
<h3>Project eCommerce</h3>
<div class="spacer"></div>
<div>
<h4>Seite</h4>
<ul>
<li><a>Login</a></li>
<li><a>Angebote</a></li>
<li><a>Suche</a></li>
<li><a>Mitarbeiter Login</a></li>
</ul>
</div>
<div>
<h4>Mehr</h4>
<ul>
<li><a>Nutzungsbedingungen</a></li>
<li><a>Datenschutz</a></li>
<li><a>Über</a></li>
</ul>
</div>
</div>
</footer>
</body>
</html>

View File

@ -1,158 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr">
<head>
<meta charset="utf-8">
<title>Frontpage</title>
<link rel="stylesheet" type="text/css" href="css/ecom.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
</head>
<body>
<nav class='hero'>
<div class='content-width bar-flex'>
<h1>Project eCommerce</h1>
<button>Angebote</button>
<div class='spacer input-icon secondary'>
<input type="text" placeholder="Nach Produkten suchen..."/>
<button>Finden</button>
</div>
<button>Login</button>
</div>
</nav>
<main class="sidebar-layout content-width">
<nav>
<ul>
<li><a>Dashboard</a>
<ul>
<li><a>Artikel</a></li>
<li><a>Umsatzsteuer</a></li>
<li><a class='selected'>Geldbuchungen</a></li>
<li><a>Einstellungen</a></li>
</ul>
</li>
<li><a>Lieferanten</a>
<ul>
<li><a>Warenbuchungen</a></li>
<li><a>Geldbuchungen</a></li>
</ul>
</li>
<li><a>Lager</a>
<ul>
<li><a>Bestandsbuchungen</a></li>
</ul>
</li>
<li><a>Kunden</a>
<ul>
<li><a>Bestellungen</a></li>
<li><a>Geldbuchungen</a></li>
</ul>
</li>
</ul>
</nav>
<div class="content-width">
<h1>Geldbuchungen</h1>
<p>
<table>
<tr>
<th>Id</th>
<th>Datum</th>
<th>Betrag</th>
<th>Gegenkonto</th>
<th>Betreff</th>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
<tr>
<td>#100</td>
<td>2019-10-08</td>
<td>100,50 €</td>
<td>Lieferant: Hans</td>
<td>Bestellungen: #41</td>
</tr>
</table>
</p>
<p>
<a class="button">Manuelle Buchung</a>
</p>
</div>
</main>
<footer class="hero-black">
<div class='content-width bar-flex'>
<h3>Project eCommerce</h3>
<div class="spacer"></div>
<div>
<h4>Seite</h4>
<ul>
<li><a>Login</a></li>
<li><a>Angebote</a></li>
<li><a>Suche</a></li>
<li><a>Mitarbeiter Login</a></li>
</ul>
</div>
<div>
<h4>Mehr</h4>
<ul>
<li><a>Nutzungsbedingungen</a></li>
<li><a>Datenschutz</a></li>
<li><a>Über</a></li>
</ul>
</div>
</div>
</footer>
</body>
</html>

View File

@ -1,48 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr">
<head>
<meta charset="utf-8">
<title>Frontpage</title>
<link rel="stylesheet" type="text/css" href="css/ecom.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
</head>
<body>
<div class='grid m center vertical-center'>
<form class='hero primary'>
<p>
<label>Nutzername</label>
<input type="text" placeholder=""/>
</p>
<p>
<label>Passwort</label>
<input type="password" placeholder=""/>
</p>
<button class='secondary'>Login</button>
</form>
</div>
<footer class="hero-black">
<div class='content-width bar-flex'>
<h3>Project eCommerce</h3>
<div class="spacer"></div>
<div>
<h4>Seite</h4>
<ul>
<li><a>Login</a></li>
<li><a>Angebote</a></li>
<li><a>Suche</a></li>
<li><a>Mitarbeiter Login</a></li>
</ul>
</div>
<div>
<h4>Mehr</h4>
<ul>
<li><a>Nutzungsbedingungen</a></li>
<li><a>Datenschutz</a></li>
<li><a>Über</a></li>
</ul>
</div>
</div>
</footer>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,11 +0,0 @@
package org.hso.ecommerce.action.shop;
import org.hso.ecommerce.entities.shop.CustomerOrder;
public class EnableTrackingAction {
public static void addTrackingInfo(CustomerOrder customerOrder) {
// TODO:
customerOrder.trackingId = "555-NASE";
}
}

View File

@ -1,7 +0,0 @@
package org.hso.ecommerce.action.warehouse;
public class StoreSupplierOrderAction {
//TODO add delivery date and warehouse booking
}

View File

@ -1,157 +0,0 @@
package org.hso.ecommerce.app;
import org.hso.ecommerce.entities.user.User;
import org.hso.ecommerce.repos.user.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Optional;
/**
* TODO clean up this class
*/
@Controller
public class RequestController {
@Autowired
private final UserRepository userRepository = null;
static int notSoRandom = 0;
@GetMapping("/login")
public String login() {
return "login";
}
@PostMapping("/login")
public String loginPost(
HttpServletRequest request,
HttpServletResponse response,
@RequestParam("username") String username,
@RequestParam("password") String password,
HttpSession session
) {
String gto = (String) session.getAttribute("afterLogin");
Optional<User> user = userRepository.findByEmail(username);
if (!user.isPresent()) {
request.setAttribute("error", "Email Adresse falsch.");
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
return "login";
}
if (!user.get().validatePassword(password)) {
request.setAttribute("error", "Passwort falsch.");
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
return "login";
}
if (!user.get().isActive) {
request.setAttribute("error", "User ist deaktiviert.");
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
return "login";
}
session.setAttribute("userId", user.get().getId());
if (gto != null && gto.startsWith("/")) {
return "redirect:" + gto;
} else {
return "redirect:/";
}
}
@PostMapping("/logout")
public String logoutPost(HttpServletResponse response,
HttpSession session
) {
session.removeAttribute("userId");
return "redirect:/";
}
@GetMapping("/intern/")
public String intern() {
return "intern/index";
}
@GetMapping("/intern/customers/")
public String internCustomers() {
return "intern/customers/index";
}
@GetMapping("/intern/customers/{id}")
public String internCustomersId() {
return "intern/customers/id";
}
@GetMapping("/intern/customerOrders/")
public String internCustomerOrder() {
return "intern/customerOrders/index";
}
@GetMapping("/intern/customerOrders/{id}")
public String internCustomerOrdersId() {
return "intern/customerOrders/id";
}
@GetMapping("/intern/accounting/")
public String accounting() {
return "intern/accounting/index";
}
@GetMapping("/intern/accounting/vat")
public String accountingVat() {
return "intern/accounting/vat";
}
@GetMapping("/intern/accounting/main")
public String accountingIntern() {
return "intern/accounting/main";
}
@GetMapping("/intern/accounting/addManual")
public String accountingAddManual() {
return "intern/accounting/addManual";
}
@GetMapping("/intern/warehouse/")
public String accountingWarehouse() {
return "intern/warehouse/index";
}
@GetMapping("/intern/warehouse/todo")
public String accountingWarehouseTodo() {
return "intern/warehouse/todo";
}
@GetMapping("/intern/warehouse/addManual")
public String accountingWarehouseAddManual() {
return "intern/warehouse/addManual";
}
@PostMapping("/intern/warehouse/progress/{id}")
public String accountingWarehouseProgressIdPost(HttpServletResponse response) {
if ((notSoRandom++) % 2 == 1) {
return "redirect:/intern/warehouse/progress/450";
} else {
response.setStatus(409);
return "intern/warehouse/error_progress_failed";
}
}
@GetMapping("/intern/warehouse/progress/{id}")
public String accountingWarehouseProgressId() {
return "intern/warehouse/id_progress";
}
@GetMapping("/intern/warehouse/slots/")
public String accountingWarehouseSlots() {
return "intern/warehouse/slots/index";
}
}

View File

@ -1,36 +0,0 @@
package org.hso.ecommerce.app;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("user")
public class UserRequestController {
@GetMapping("/")
public String user() {
return "redirect:/user/settings";
}
@GetMapping("/settings")
public String userSettings() {
return "user/settings";
}
@GetMapping("/orders/")
public String userOrdeers() {
return "user/orders/index";
}
@GetMapping("/bonuspoints")
public String userBonuspoints() {
return "user/bonuspoints";
}
@GetMapping("/notifications/")
public String userNotifications() {
return "user/notifications/index";
}
}

View File

@ -1,8 +0,0 @@
package org.hso.ecommerce.controller;
import org.springframework.stereotype.Controller;
@Controller
//@RequestMapping("...")
public class BookingController {
}

View File

@ -1,8 +0,0 @@
package org.hso.ecommerce.controller;
import org.springframework.stereotype.Controller;
@Controller
//@RequestMapping("...")
public class LoginController {
}

View File

@ -1,74 +0,0 @@
package org.hso.ecommerce.controller;
import org.hso.ecommerce.entities.shop.Address;
import org.hso.ecommerce.entities.user.User;
import org.hso.ecommerce.repos.user.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Optional;
@Controller
public class RegisterController {
@Autowired
private final UserRepository userRepository = null;
@PostMapping("/register")
public String registerPost(
HttpServletRequest request,
HttpServletResponse response,
@RequestParam("username") String username,
@RequestParam("password") String password,
@RequestParam("password2") String password2,
@RequestParam("salutation") String salutation,
@RequestParam("name") String name,
@RequestParam("address") String address,
@RequestParam("type") String type,
@RequestParam("ad") String ad
)
{
Optional<User> user = userRepository.findByEmail(username);
if (user.isPresent()) {
request.setAttribute("error", "Email Adresse existiert bereits!");
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
return "register";
}
if (!password.equals(password2)){
request.setAttribute("error", "Passwörter sind nicht gleich");
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return "register";
}
//set values for new user
User newUser = new User();
newUser.email = username;
newUser.setPassword(password);
newUser.email = username;
newUser.isEmployee = false;
//TODO for salutation, type, ad are no attributes/fields in the class/database. Add when they are there.
newUser.isActive = true;
newUser.created = new java.sql.Timestamp(System.currentTimeMillis());
Address newAddress = new Address();
newAddress.name = name;
newAddress.addressString = address;
newUser.defaultDeliveryAddress = newAddress;
userRepository.save(newUser); // save newUser
return "redirect:/login";
}
@GetMapping("/register")
public String register() {
return "register";
}
}

View File

@ -1,8 +0,0 @@
package org.hso.ecommerce.controller;
import org.springframework.stereotype.Controller;
@Controller
//@RequestMapping("...")
public class UserController {
}

View File

@ -1,331 +0,0 @@
package org.hso.ecommerce.controller.cronjob;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import org.hso.ecommerce.action.booking.CreateBookingAction;
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction;
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
import org.hso.ecommerce.action.cronjob.ReorderAction;
import org.hso.ecommerce.action.cronjob.UpdateOffersAction;
import org.hso.ecommerce.entities.booking.Booking;
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
import org.hso.ecommerce.entities.booking.BookingReason;
import org.hso.ecommerce.entities.cron.BackgroundJob;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.supplier.ArticleOffer;
import org.hso.ecommerce.entities.supplier.Supplier;
import org.hso.ecommerce.entities.supplier.SupplierOrder;
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
import org.hso.ecommerce.repos.booking.BookingRepository;
import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.shop.CustomerOderRepository;
import org.hso.ecommerce.repos.supplier.ArticleOfferRepository;
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
import org.hso.ecommerce.repos.supplier.SupplierRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
interface ICronjob {
/**
* Calculate the earliest cronjob execution time that happens after the given reference time.
*
* @param reference Position in time to start searching. The implementor is allowed to modify the reference time.
* @return A new Calendar instance (or the same) containing the time for next execution.
*/
Calendar nextExecution(Calendar reference);
/**
* Calculate the latest cronjob execution time that happens before or exactly at the given refernce time.
*
* @param reference Position in time to start searching. The implementor is allowed to modify the reference time.
* @return A new Calendar instance (or the same) containing the time of the last execution.
*/
Calendar previousExecution(Calendar reference);
/**
* Execute this cronjob.
*
* @param time The point in time this execution was scheduled. In case of a missed cronjob, the actual time of
* this call might be much later.
* @param controller Back-reference that allows to use repositories.
*/
void executeAt(Calendar time, CronjobController controller);
}
@Component
class Reorder implements ICronjob {
@Override
public Calendar nextExecution(Calendar reference) {
if (reference.get(Calendar.HOUR_OF_DAY) >= 8) {
reference.add(Calendar.DAY_OF_MONTH, 1);
}
reference.set(Calendar.HOUR_OF_DAY, 8);
reference.set(Calendar.MINUTE, 0);
reference.set(Calendar.SECOND, 0);
reference.set(Calendar.MILLISECOND, 0);
return reference;
}
@Override
public Calendar previousExecution(Calendar reference) {
if (reference.get(Calendar.HOUR_OF_DAY) < 8) {
reference.add(Calendar.DAY_OF_MONTH, -1);
}
reference.set(Calendar.HOUR_OF_DAY, 8);
reference.set(Calendar.MINUTE, 0);
reference.set(Calendar.SECOND, 0);
reference.set(Calendar.MILLISECOND, 0);
return reference;
}
/**
* Calculates the amount of ordered articles by customers for the given article type in the time between begin and
* end.
*
* @param article The article to search orders for.
* @param begin The start time for the search (included)
* @param end The end time for the search (excluded)
* @return The number of articles that were ordered by customers in the given range.
*/
private Integer getOrderedAmounts(Article article, Calendar begin, Calendar end, CronjobController controller) {
return controller.customerOrderRepository.countOrdersOfArticleInTimespan(
article.id,
new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
}
/**
* Calculates the amount of ordered articles by customers for the given article type in the three days before the
* given reference time. The return-array contains 3 fields: Index 0: Orders 72 to 48 hours ago; Index 1: Orders 48
* to 24 hours ago; Index 2: Orders 24 to 0 hours ago.
*
* @param article The article for which the customer orders are checked.
* @param time The reference time to use for calculation of the last orders.
* @return A 3-element array containing the orders of the last three days.
*/
private Integer[] getOrderedAmounts(Article article, Calendar time, CronjobController controller) {
Calendar oneDayBefore = (Calendar) time.clone();
oneDayBefore.add(Calendar.DAY_OF_MONTH, -1);
Calendar twoDaysBefore = (Calendar) time.clone();
twoDaysBefore.add(Calendar.DAY_OF_MONTH, -2);
Calendar threeDaysBefore = (Calendar) time.clone();
threeDaysBefore.add(Calendar.DAY_OF_MONTH, -3);
return new Integer[] { //
getOrderedAmounts(article, threeDaysBefore, twoDaysBefore, controller), //
getOrderedAmounts(article, twoDaysBefore, oneDayBefore, controller), //
getOrderedAmounts(article, oneDayBefore, time, controller), //
};
}
private HashMap<ArticleIdentifier, ArticleOffer> mapArticleOffers(List<ArticleOffer> articleOffers) {
HashMap<ArticleIdentifier, ArticleOffer> map = new HashMap<>();
for (ArticleOffer articleOffer : articleOffers) {
ArticleIdentifier identifier = new ArticleIdentifier(articleOffer.manufacturer, articleOffer.articleNumber);
map.put(identifier, articleOffer);
}
return map;
}
@Override
public void executeAt(Calendar time, CronjobController controller) {
List<Supplier> suppliers = controller.supplierRepository.findAll();
ReadSupplierDataAction.Result supplierData = new ReadSupplierDataAction(suppliers).finish();
// Save the new offers in the database
List<ArticleOffer> allOffers = controller.articleOfferRepository.findAll();
allOffers = new UpdateOffersAction(allOffers, supplierData.cheapestOffer).finish();
controller.articleOfferRepository.saveAll(allOffers);
HashMap<ArticleIdentifier, ArticleOffer> mappedOffers = mapArticleOffers(allOffers);
// Reorder
List<Article> allArticles = controller.articleRepository.findAll();
for (Article article : allArticles) {
Integer[] orderedAmounts = getOrderedAmounts(article, time, controller);
Integer undeliveredReorders = controller.supplierOrderRepository
.countUndeliveredReorders(article.related.articleNumber);
int amountInStock = controller.warehouseBookingPositionSlotEntryRepository.getArticleStock(article.id)
.orElse(0);
ReorderAction action = new ReorderAction(article, orderedAmounts,
undeliveredReorders,
amountInStock,
supplierData.cheapestOffer, mappedOffers);
SupplierOrder order = action.finish();
if (order != null) {
controller.supplierOrderRepository.save(order);
// Create bookings for this order
int netPrice = order.totalPriceNet;
int vatPercent = order.ordered.vatPercent;
int vatAmount = netPrice * vatPercent / 100;
int grossPrice = netPrice + vatAmount;
// Obligation towards the supplier
BookingAccountEntry mainAccount = controller.bookingAccountEntryRepository.getByMain()
.orElseGet(BookingAccountEntry::newMain);
BookingAccountEntry supplierAccount = controller.bookingAccountEntryRepository
.getBySupplier(order.supplier.id)
.orElseGet(() -> BookingAccountEntry.newSupplier(order.supplier));
BookingReason obligationReason = new BookingReason(order);
Booking obligationBooking = new CreateBookingAction(mainAccount,
supplierAccount,
obligationReason,
grossPrice).finish();
controller.bookingRepository.save(obligationBooking);
// Input Tax
BookingAccountEntry vatAccount = controller.bookingAccountEntryRepository.getByVat()
.orElseGet(BookingAccountEntry::newVat);
mainAccount = controller.bookingAccountEntryRepository.getByMain().get();
BookingReason inputTaxReason = new BookingReason(order);
Booking inputTaxBooking = new CreateBookingAction(vatAccount, mainAccount, inputTaxReason, vatAmount)
.finish();
controller.bookingRepository.save(inputTaxBooking);
}
}
}
}
class ScheduledCronjob {
public final Calendar executionTime;
public final ICronjob cronjob;
public final BackgroundJob model;
public ScheduledCronjob(Calendar executionTime, ICronjob cronjob, BackgroundJob model) {
this.executionTime = executionTime;
this.cronjob = cronjob;
this.model = model;
}
}
@Component
class CronjobController {
private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
private static final Map<String, ICronjob> cronjobs = getCronjobs();
@Autowired
private final BackgroundJobRepository cronjobRepository = null;
@Autowired
final ArticleRepository articleRepository = null;
@Autowired
final ArticleOfferRepository articleOfferRepository = null;
@Autowired
final CustomerOderRepository customerOrderRepository = null;
@Autowired
final BookingRepository bookingRepository = null;
@Autowired
final BookingAccountEntryRepository bookingAccountEntryRepository = null;
@Autowired
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
@Autowired
final SupplierRepository supplierRepository = null;
@Autowired
final SupplierOrderRepository supplierOrderRepository = null;
private static Map<String, ICronjob> getCronjobs() {
HashMap<String, ICronjob> map = new HashMap<>();
// Register all existing cronjobs
map.put(BackgroundJob.JOB_REORDER, new Reorder());
return Collections.unmodifiableMap(map);
}
private ScheduledCronjob getNextCronjob() {
Calendar currentTime = new GregorianCalendar();
Iterable<BackgroundJob> jobs = cronjobRepository.findAll();
HashMap<String, BackgroundJob> alreadyExecuted = new HashMap<>();
for (BackgroundJob job : jobs) {
alreadyExecuted.put(job.jobName, job);
}
ScheduledCronjob earliestJob = null;
for (Entry<String, ICronjob> entry : cronjobs.entrySet()) {
ScheduledCronjob resultingJob;
BackgroundJob dbEntry = alreadyExecuted.get(entry.getKey());
if (dbEntry != null) {
Calendar previousExecution = new GregorianCalendar();
previousExecution.setTimeInMillis(dbEntry.lastExecution.getTime());
Calendar followingSchedule = entry.getValue().nextExecution((Calendar) previousExecution.clone());
Calendar lastSchedule = entry.getValue().previousExecution((Calendar) currentTime.clone());
if (lastSchedule.getTimeInMillis() > followingSchedule.getTimeInMillis()) {
// This happens, if more than one execution was missed.
// In this case, run the job only once.
followingSchedule = lastSchedule;
}
resultingJob = new ScheduledCronjob(followingSchedule, entry.getValue(), dbEntry);
} else {
// This cronjob has never been executed before.
Calendar lastScheduleTime = entry.getValue().previousExecution((Calendar) currentTime.clone());
BackgroundJob model = new BackgroundJob();
model.jobName = entry.getKey();
resultingJob = new ScheduledCronjob(lastScheduleTime, entry.getValue(), model);
}
// Look for the job with earliest executionTime - it will run next
if (earliestJob == null
|| resultingJob.executionTime.getTimeInMillis() < earliestJob.executionTime.getTimeInMillis()) {
earliestJob = resultingJob;
}
}
return earliestJob;
}
private void runCronjobExecutionLoop() {
Thread.currentThread().setName("Cronjob");
try {
while (true) {
ScheduledCronjob nextJob = getNextCronjob();
if (nextJob == null) {
// In case there are no cronjobs
return;
}
long waitingTime = nextJob.executionTime.getTimeInMillis() - System.currentTimeMillis();
if (waitingTime > 0) {
Thread.sleep(waitingTime);
}
try {
nextJob.cronjob.executeAt(nextJob.executionTime, this);
} catch (Throwable t) {
log.error("Failed to execute cronjob " + nextJob.cronjob.getClass() + ":");
t.printStackTrace();
}
nextJob.model.lastExecution = new Timestamp(nextJob.executionTime.getTimeInMillis());
cronjobRepository.save(nextJob.model);
}
} catch (InterruptedException e) {
log.error("The cronjob execution thread has been interrupted");
}
}
@PostConstruct
public void onPostConstruct() {
new Thread(this::runCronjobExecutionLoop).start();
}
}

View File

@ -1,8 +0,0 @@
package org.hso.ecommerce.controller.intern;
import org.springframework.stereotype.Controller;
@Controller
//@RequestMapping("...")
public class InternIndexController {
}

View File

@ -1,8 +0,0 @@
package org.hso.ecommerce.controller.intern;
import org.springframework.stereotype.Controller;
@Controller
//@RequestMapping("...")
public class WarehouseController {
}

View File

@ -1,8 +0,0 @@
package org.hso.ecommerce.controller.intern.customers;
import org.springframework.stereotype.Controller;
@Controller
//@RequestMapping("...")
public class CustomerOrderController {
}

View File

@ -1,8 +0,0 @@
package org.hso.ecommerce.controller.intern.customers;
import org.springframework.stereotype.Controller;
@Controller
//@RequestMapping("...")
public class CustomersIndexController {
}

View File

@ -1,89 +0,0 @@
package org.hso.ecommerce.controller.intern.suppliers;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.hso.ecommerce.entities.supplier.SupplierOrder;
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.view.RedirectView;
@Controller
@RequestMapping("/intern/")
public class SupplierOrderController {
@Autowired
private final SupplierOrderRepository supplierOrderRepository = null;
@GetMapping("supplierOrders")
public String listSuppliers(Model model) {
List<UImodelSupplierOrder> totals = new ArrayList<UImodelSupplierOrder>();
for (SupplierOrder orders : supplierOrderRepository.findAll()) {
totals.add(new UImodelSupplierOrder(orders));
}
model.addAttribute("orders", totals);
return "intern/supplierOrders/index";
}
@PostMapping("/supplierOrders/store/{id}")
public RedirectView storeOrder(@PathVariable(required = true) String id) {
long supplierOrderID = Long.parseLong(id);
Optional<SupplierOrder> order = supplierOrderRepository.findById(supplierOrderID);
if (order.isPresent()) {
// TODO call action
System.out.println("Order is present\n");
}
return new RedirectView("../../supplierOrders/");
}
public class UImodelSupplierOrder {
public long id;
public String dateOrder;
public String supplierName;
public String articleName;
public long articleId;
public String priceNet;
public String quantity;
public String priceTotal;
public boolean arrived;
public UImodelSupplierOrder(SupplierOrder order) {
this.id = order.id;
this.supplierName = order.supplier.name;
this.articleName = order.ordered.title;
this.articleId = order.ordered.id;
this.priceNet = String.format("%.2f", ((float) order.pricePerUnitNetCent / 100));
this.quantity = String.valueOf(order.numberOfUnits);
this.priceTotal = String.format("%.2f", ((float) order.totalPriceNet / 100));
Date date = new Date();
date.setTime(order.created.getTime());
this.dateOrder = new SimpleDateFormat("dd.MM.yyyy").format(date);
if (order.delivered != null) {
arrived = true;
} else {
arrived = false;
}
}
}
}

View File

@ -1,34 +0,0 @@
package org.hso.ecommerce.entities.warehouse;
import org.hso.ecommerce.entities.shop.CustomerOrder;
import org.hso.ecommerce.entities.supplier.SupplierOrder;
import javax.persistence.*;
@Entity
@Table(name = "warehouse_booking_reasons")
public class WarehouseBookingReason {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic
public long id;
public String comment;
@ManyToOne(optional = true)
public SupplierOrder causeSupplierOrder;
@ManyToOne(optional = true)
public CustomerOrder customerOrder;
public boolean isManuel;
// Default Constructor is needed for construction by ORM
public WarehouseBookingReason() {
}
public WarehouseBookingReason(CustomerOrder order) {
this.customerOrder = order;
}
}

View File

@ -1,17 +0,0 @@
package org.hso.ecommerce.repos.booking;
import java.util.List;
import org.hso.ecommerce.entities.booking.Booking;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
@Repository
public interface BookingRepository extends JpaRepository<Booking, Long> {
// Return a list with all bookings entries, sorted by id
@Query(value = "SELECT * FROM bookings as b INNER JOIN booking_account_entries ON b.destination_id=booking_account_entries.id OR b.source_id=booking_account_entries.id WHERE booking_account_entries.supplier_account_id = :supplier ORDER BY b.id DESC", nativeQuery = true)
List<Booking> getBySupplier(Long supplier);
}

View File

@ -1,38 +0,0 @@
package org.hso.ecommerce.repos.shop;
import org.hso.ecommerce.entities.shop.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface ArticleRepository extends JpaRepository<Article, Long> {
@Query("SELECT a FROM Article a WHERE a.id = :articleId")
Article findArticleById(@Param("articleId") long articleId);
@Query("SELECT a FROM Article a")
List<Article> findAll();
@Query(value = "Select a.* from articles as a, article_offers as ao, warehouse_booking_position_entries as wbpe where a.related_id = ao.id and wbpe.article_id = a.id and ao.should_be_advertised = true group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
List<Article> getAdvertisedArticles();
@Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC")
List<Article> getOrderedArticles();
@Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a WHERE c.id = :customerId ORDER BY co.id DESC")
List<Article> getOrderedArticles(long customerId);
@Query(value = "SELECT a.id FROM articles a WHERE a.related_id = :relatedId", nativeQuery = true)
Optional<Integer> findArticleIDByRelatedID(@Param("relatedId") long relatedId);
@Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.title LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
List<Article> getArticlesByTerm(String term);
@Query(value = "Select a.* from articles as a, categories as c, article_categories_bindings as acb, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and acb.articles_id = a.id and acb.categories_id = c.id and c.name = :category group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
List<Article> getArticlesByCategory(String category);
}

View File

@ -1,17 +0,0 @@
package org.hso.ecommerce.repos.shop;
import org.hso.ecommerce.entities.shop.CustomerOrder;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
@Repository
public interface CustomerOderRepository extends JpaRepository<CustomerOrder, Long> {
@Query("SELECT SUM(cop.quantity) FROM CustomerOrderPosition cop JOIN cop.order co WHERE cop.article.id = :articleId AND co.created >= :begin AND co.created < :end")
Integer countOrdersOfArticleInTimespan(
long articleId, java.sql.Timestamp begin, java.sql.Timestamp end
);
}

View File

@ -1,18 +0,0 @@
package org.hso.ecommerce.repos.user;
import org.hso.ecommerce.entities.user.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT c FROM User c WHERE c.email = :email")
Optional<User> findByEmail(String email);
}

View File

@ -1,118 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Artikelübersicht</title>
<script th:src="@{/js/filterTable.js}"></script>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
<body>
<nav th:replace="fragments/header :: header">Header</nav>
<div class="sidebar-layout content-width">
<nav></nav>
<div>
<h1>Bestellung 1010</h1>
<script th:src="@{/js/back.js}"></script>
<div class="back" data-group="intern" data-insert="true"></div>
</div>
</div>
<main class="sidebar-layout content-width">
<nav th:replace="fragments/intern :: sidebar"></nav>
<div class="content-width">
<div>
<h2 id="20202701"> Bestellung vom 27.01.2020 </h2>
<div>
<table class="key-value">
<tr>
<th>Nutzer</th>
<td><a th:href="@{/intern/customers/498}">K-4850</a></td>
</tr>
<tr>
<th>Lieferstatus</th>
<td><b>Unterwegs</b> <br/> Vorraussichtliche Ankunft: 29.01.2020</td>
</tr>
<tr>
<th>Sendeverfolgungsnummer</th>
<td>XE51451436DE</td>
</tr>
<tr>
<th></th>
<td>
Hans Maier <br/>
Hauptstraße 12<br/>
74880 Musterstadt<br/>
Deutschland <br/>
</td>
</tr>
<tr>
<th>Eingelösste Bonuspunkte</th>
<td>10</td>
</tr>
</table>
</div>
<table>
<tr>
<th>Bild</th>
<th>Name</th>
<th>Menge</th>
<th>Preis (Brutto)</th>
</tr>
<tr>
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-1.jpg}" class="s"/><a></td>
<td><a th:href="@{/shop/articles/4151}">Kamera<a/></td>
<td> 1</td>
<td>100,50&nbsp;EUR</td>
</tr>
<tr>
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-2.jpg}" class="s"/><a/></td>
<td><a th:href="@{/shop/articles/4151}">Earbuds<a/></td>
<td> 3</td>
<td>63,95&nbsp;EUR</td>
</tr>
<tr>
<th></th>
<th></th>
<th>Position</th>
<th>Preis</th>
</tr>
<tr>
<td></td>
<td></td>
<td>Artikel (Netto)</td>
<td> 120,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Bonuspunkte</td>
<td> 5,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Umsatzsteuer (19%)</td>
<td> 42,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>
<h3>Gesammtpreis</h3>
</td>
<td>
<h3>240,79&nbsp;EUR</h3>
</td>
</tr>
</table>
</div>
</div>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

View File

@ -1,129 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Kunden</title>
<script th:src="@{/js/filterTable.js}"></script>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
<body>
<nav th:replace="fragments/header :: header">Header</nav>
<div class="sidebar-layout content-width">
<nav></nav>
<div>
<h1>Kunden</h1>
<script th:src="@{/js/back.js}"></script>
<div class="back" data-group="intern" data-name="Zurück zur Kundenübersicht." data-insert="false"></div>
</div>
</div>
<main class="sidebar-layout content-width">
<nav th:replace="fragments/intern :: sidebar"></nav>
<div class="content-width">
<p>
<table id="main-table">
<tr>
<th colspan="7">
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
data-target-id="main-table"></input>
</th>
</tr>
<tr>
<th>Kundennummer</th>
<th>Beitrittsdatum</th>
<th>Name</th>
<th>E-Mail</th>
<th>Status</th>
<th></th>
</tr>
<tr>
<td>1209</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td>Geschäftskunde</td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1208</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td>Inaktiv, Geschäftskunde</td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1207</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td></td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1206</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td></td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1205</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td></td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1204</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td></td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1203</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td></td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1202</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td></td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1201</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>hans.maier@example.com</td>
<td>Inaktiv, Mitarbeiter</td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
<tr>
<td>1214</td>
<td>2019-11-10</td>
<td>Hans Maier</td>
<td>admin@example.com</td>
<td>Mitarbeiter</td>
<td><a th:href="@{/intern/customers/4884}" class="button smaller">Details</a></td>
</tr>
</table>
</p>
</div>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

View File

@ -1,58 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>e-commerce</title>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
<body>
<body>
<main class="modal l">
<div class="detailflex l">
<h1>Erfolgreich zugewiesen.</h1>
<p>
<table id="main-table">
<tr>
<th>Zeitpunkt</th>
<th>Artikel</th>
<th>Anzahl</th>
<th>Von</th>
<th>Nach</th>
</tr>
<!-------------------------------------------------------------->
<tr data-group="3">
<td>2020-01-12 12:18</td>
<td colspan="4" class="l">
<a th:href="@{/intern/customerOrders/4808}">Bestellung 8408</a>
<div>
Hans Maier <br/>
Hauptstraße 12<br/>
74880 Musterstadt<br/>
Deutschland <br/>
</div>
</td>
</tr>
<tr data-group="3">
<td><img th:src="@{/img/product-1.jpg}" class="s"/></td>
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
<td>1</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%231}">Lagerplatz 01</a></td>
<td> -</td>
</tr>
<tr data-group="3">
<td><img th:src="@{/img/product-2.jpg}" class="s"/></td>
<td><a th:href="@{/intern/listedArticles/4205}">Spielzeugauto</a></td>
<td>2</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%232}">Lagerplatz 02</a></td>
<td> -</td>
</tr>
</table>
</p>
<a class="secondary button" th:href="@{/intern/warehouse/todo}"> Abschließen </a>
</div>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

View File

@ -1,127 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Lager</title>
<script th:src="@{/js/filterTable.js}"></script>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
<body>
<nav th:replace="fragments/header :: header">Header</nav>
<div class="sidebar-layout content-width">
<nav></nav>
<div>
<h1>Lagerbuchungen</h1>
<script th:src="@{/js/back.js}"></script>
<div class="back" data-group="intern" data-name="Zurück zu den Lagerbuchungen." data-insert="false"></div>
</div>
</div>
<main class="sidebar-layout content-width">
<nav th:replace="fragments/intern :: sidebar"></nav>
<div class="content-width">
<p>
Die Lagerbestände nach Artikel können Sie unter den <a th:href="@{/intern/listedArticles/}">gelisteten
Artikeln</a> einsehen.
</p>
<p>
<table id="main-table">
<tr>
<th colspan="7">
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
data-target-id="main-table"></input>
</th>
</tr>
<tr>
<th>Zeitpunkt</th>
<th>Artikel</th>
<th>Anzahl</th>
<th>Von</th>
<th>Nach</th>
<th>Status</th>
</tr>
<!-------------------------------------------------------------->
<tr data-group="3">
<td>2020-01-12 12:18</td>
<td colspan="4" class="l">
<a th:href="@{/intern/customerOrders/4808}">Bestellung 8408</a>
</td>
<td>Auf Warteliste <br/>
</td>
</tr>
<tr data-group="3">
<td></td>
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
<td>1</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%231}">Lagerplatz 01</a></td>
<td> -</td>
<td></td>
</tr>
<tr data-group="3">
<td></td>
<td><a th:href="@{/intern/listedArticles/4205}">Spielzeugauto</a></td>
<td>2</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%232}">Lagerplatz 02</a></td>
<td> -</td>
<td></td>
</tr>
<!-------------------------------------------------------------->
<tr data-group="2">
<td>2020-01-12 12:15</td>
<td colspan="4" class="l">
Manuell: Ware war defekt.
</td>
<td>In Arbeit <br/>
</td>
</tr>
<tr data-group="2">
<td></td>
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
<td>1</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%231}">Lagerplatz 01</a></td>
<td> -</td>
<td></td>
</tr>
<!-------------------------------------------------------------->
<tr data-group="1">
<td>2020-01-12 12:11</td>
<td colspan="4" class="l">
<a th:href="@{/intern/supplierOrders/#q=4545}">Lieferung 4545</a>
</td>
<td>Fertig <br/></td>
</tr>
<tr data-group="1">
<td></td>
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
<td>10</td>
<td> -</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%231}">Lagerplatz 01</a>
</th>
<td></td>
</tr>
<tr data-group="1">
<td></td>
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
<td>1</td>
<td> -</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%234}">Lagerplatz 04</a></td>
<td></td>
</tr>
</table>
</p>
</div>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

View File

@ -1,105 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Packliste</title>
<script th:src="@{/js/filterTable.js}"></script>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
<body>
<nav th:replace="fragments/header :: header">Header</nav>
<div class="sidebar-layout content-width">
<nav></nav>
<div>
<h1>Packliste</h1>
<script th:src="@{/js/back.js}"></script>
<div class="back" data-group="intern" data-name="Zurück zur Packliste." data-insert="false"></div>
</div>
</div>
<main class="sidebar-layout content-width">
<nav th:replace="fragments/intern :: sidebar"></nav>
<div class="content-width">
<p>
<table id="main-table">
<tr>
<th colspan="7">
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
data-target-id="main-table"></input>
</th>
</tr>
<tr>
<th>Zeitpunkt</th>
<th>Artikel</th>
<th>Anzahl</th>
<th>Von</th>
<th>Nach</th>
<th>Status</th>
</tr>
<!-------------------------------------------------------------->
<tr data-group="3">
<td>2020-01-12 12:18</td>
<td colspan="4" class="l">
<a th:href="@{/intern/customerOrders/4808}">Bestellung 8408</a>
<div>
Hans Maier <br/>
Hauptstraße 12<br/>
74880 Musterstadt<br/>
Deutschland <br/>
</div>
</td>
<td>
<form th:action="@{/intern/warehouse/progress/5410}" method="post">
<button type="submit">Beginnen</button>
</form>
</td>
</tr>
<tr data-group="3">
<td><img th:src="@{/img/product-1.jpg}" class="s"/></td>
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
<td>1</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%231}">Lagerplatz 01</a></td>
<td> -</td>
<td></td>
</tr>
<tr data-group="3">
<td><img th:src="@{/img/product-2.jpg}" class="s"/></td>
<td><a th:href="@{/intern/listedArticles/4205}">Spielzeugauto</a></td>
<td>2</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%232}">Lagerplatz 02</a></td>
<td> -</td>
<td></td>
</tr>
<!-------------------------------------------------------------->
<tr data-group="2">
<td>2020-01-12 12:15</td>
<td colspan="4" class="l">
Manuell: Ware war defekt.
</td>
<td><a class="secondary button">Abschließen</a>
</td>
</tr>
<tr data-group="2">
<td><img th:src="@{/img/product-1.jpg}" class="s"/></td>
<td><a th:href="@{/intern/listedArticles/45015}">Kamera</a></td>
<td>1</td>
<td><a th:href="@{/intern/warehouse/slots/#q=%231}">Lagerplatz 01</a></td>
<td> -</td>
<td></td>
</tr>
</table>
</p>
</div>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

View File

@ -1,97 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Neuen Account erstellen</title>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
<script th:src="@{/js/scrollToContent.js}"></script>
</head>
<body>
<nav th:replace="fragments/header :: header">Header</nav>
<main class="modal">
<form class="detailflex m" th:action="@{/register}" method="POST">
<div>
<h1>Neuen Account erstellen</h1>
</div>
<div>
<h2> Login Daten </h2>
</div>
<div>
<label for="username">Email Adresse</label>
<input class="full-width" type="text" name="username" placeholder="Email Adresse" id="username" required>
</div>
<div>
<label for="password">Passwort</label>
<input class="full-width" type="password" name="password" placeholder="Passwort" id="password" required>
</div>
<div>
<label for="password2">Passwort wiederholen</label>
<input class="full-width" type="password" name="password2" placeholder="Passwort" id="password2" required>
</div>
<div>
<h2> Rechungs- und Lieferinformation </h2>
</div>
<div class="col-2">
<div>
<label for="salutation">Anrede</label>
<input class="full-width" list="salutationsOpt" name="salutation" id="salutation" placeholder="Anrede"
required/>
<datalist id="salutationsOpt">
<option value="Herr">
<option value="Frau">
<option value="Herr Dr.">
<option value="Frau Dr.">
</datalist>
</div>
<div>
<label for="name">Name</label>
<input class="full-width" type="text" name="name" id="name" placeholder="Nachname Vorname" required/>
</div>
</div>
<div>
<label for="address">Anschrift</label>
<textarea rows="5" class="full-width" type="text" name="address" id="address"
placeholder="Optional: Zusatz&#10;Optional: Unternehmen&#10;Straße Hausnummer&#10;Postleitzeit Ort&#10;Land"></textarea>
</div>
<fieldset>
<input type="radio" name="type" value="priv" id="type-priv" required>
<label for="type-priv">Ich bin Privatkunde.</label> <br/>
<input type="radio" name="type" value="bus" id="type-bus" required>
<label for="type-bus">Ich bin Geschäftskunde.</label> <br/>
</fieldset>
<div>
<h2> Werbung </h2>
</div>
<div>
<fieldset>
<input type="radio" name="ad" value="y" id="ad-y" required>
<label for="type-priv">Ich möchte Werbung erhalten.</label> <br/>
<input type="radio" name="ad" value="n" id="ad-n" required>
<label for="type-bus">Ich möchte keine Werbung erhalten.</label> <br/>
</fieldset>
</div>
<div>
<button class="full-width" type="submit" name="action" value="login">Registeren</button>
<a th:href="@{/terms}">
Unsere AGBs finden sie hier.
</a>
</div>
</form>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

View File

@ -1,57 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Bonusprogramm</title>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
<body>
<nav th:replace="fragments/header :: header">Header</nav>
<div class="sidebar-layout content-width">
<nav></nav>
<div>
<h1>Bonusprogramm</h1>
</div>
</div>
<main class="sidebar-layout content-width">
<nav th:replace="fragments/customer :: sidebar"></nav>
<div class="content-width">
<div class="grid xl">
<div class="card">
<h2> Ihr Bonuspunktestand beträgt: </h2>
<h1 class="huge"> 15 </h1>
</div>
<div class="s">
<h2> Bonuspunkte sichern </h2>
<p>
Sie sichern sich automatisch bei jedem Einkaufen pro Angefangenen
10&nbsp;EUR einen Bonuspunkt.
</p>
<p>
Eine Übersicht ihrer Bonuspunkt finden sie hier auf dieser
Bonus.
</p>
<p>
Um die Bonuspunkte einzulösen hacken sie einfach
"Bonuspunkte" verwenden beim Abschließen der Bestellung
an. Für jeden Bonuspunkt wird ihnen 0,50&nbsp;EUR gutgeschrieben.
</p>
</div>
<div class="s">
<img th:src="@{/img/undraw_gift.svg}"/>
</div>
<div class="spacer"></div>
<div class="spacer"></div>
<div class="spacer"></div>
</div>
</div>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

View File

@ -1,92 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Meine Benachrichtigungen</title>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
<body>
<nav th:replace="fragments/header :: header">Header</nav>
<div class="sidebar-layout content-width">
<nav></nav>
<div>
<h1>Meine Benachrichtigungen</h1>
</div>
</div>
<main class="sidebar-layout content-width">
<nav th:replace="fragments/customer :: sidebar"></nav>
<div>
<div class="grid xl">
<section class="notification unread">
<h2>Nachricht vom 17.08.2020, 14:38 Uhr</h2>
<h3>Ihre Bestellung kommt voraussichtlich am Donnerstag, den 20.08.2020</h3>
<p>
Vielen Dank für Ihre Bestellung der folgenden Artikel:<br>
<br>
2x tolle Kamera<br>
1x Bluetooth Kopfhörer<br>
3x USB-Magic Light<br>
<br>
Die Sendung wird Ihnen voraussichtlich am Donnerstag, den 20.08.2020 zugestellt.
Den aktuellen Status des Pakets können Sie jederzeit in der <a th:href="@{/shop/orders/}">Bestellübersicht</a>
nachvollziehen.
</p>
<button type="button" name="button">Als gelesen makieren</button>
</section>
<section class="notification">
<h2>Nachricht vom 15.08.2020, 16:38 Uhr</h2>
<h3>Jetzt unsere Tagesangebote entdecken.</h3>
<p>
Entdecken sie jetzt unseren neusten Angebote:
</p>
<div class="flowflex">
<div>
<a th:href="@{/shop/articles/1234}" class="section">
<h3>Lorem Ipsum</h3>
<img th:src="@{/img/product-2.jpg}" class="s"/>
<p>Nur 15,00&nbsp;EUR</p>
</a>
</div>
<div>
<a th:href="@{/shop/articles/1234}" class="section">
<h3>Stativ</h3>
<img th:src="@{/img/product-4.jpg}" class="s"/>
<p>Nur 7,00&nbsp;EUR</p>
</a>
</div>
<div>
<a th:href="@{/shop/articles/1234}" class="section">
<h3>Ersatzfernbedinung</h3>
<img th:src="@{/img/product-6.jpg}" class="s"/>
<p>Nur 17,00&nbsp;EUR</p>
</a>
</div>
</div>
</section>
<section class="notification">
<h2>Nachricht vom 13.08.2020, 14:38 Uhr</h2>
<h3>Ihre Bestellung ist angekommen.</h3>
<p>
Vielen Dank für Ihre Bestellung der folgenden Artikel:<br>
<br>
3x USB-Magic Light<br>
<br>
Ihre Bestellungen ist angekommen.
</p>
</section>
<section class="spacer"></section>
<section class="spacer"></section>
<section class="spacer"></section>
</div>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

View File

@ -1,193 +0,0 @@
<!DOCTYPE html>
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
<title>Meine Bestellungen</title>
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
</head>
<body>
<nav th:replace="fragments/header :: header">Header</nav>
<div class="sidebar-layout content-width">
<nav></nav>
<div>
<h1>Meine Bestellungen</h1>
</div>
</div>
<main class="sidebar-layout content-width">
<nav th:replace="fragments/customer :: sidebar"></nav>
<div class="content-width detailflex">
<div>
<h2 id="20202701"> Bestellung vom 27.01.2020 </h2>
<div>
<table class="key-value">
<tr>
<th>Lieferstatus</th>
<td><b>Unterwegs</b> <br/> Vorraussichtliche Ankunft: 29.01.2020</td>
</tr>
<tr>
<th>Sendeverfolgungsnummer</th>
<td>XE51451436DE</td>
</tr>
<tr>
<th></th>
<td>
Hans Maier <br/>
Hauptstraße 12<br/>
74880 Musterstadt<br/>
Deutschland <br/>
</td>
</tr>
<tr>
<th>Eingelösste Bonuspunkte</th>
<td>10</td>
</tr>
</table>
</div>
<table>
<tr>
<th>Bild</th>
<th>Name</th>
<th>Menge</th>
<th>Preis (Brutto)</th>
</tr>
<tr>
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-1.jpg}" class="s"/><a></td>
<td><a th:href="@{/shop/articles/4151}">Kamera<a/></td>
<td> 1</td>
<td>100,50&nbsp;EUR</td>
</tr>
<tr>
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-2.jpg}" class="s"/><a/></td>
<td><a th:href="@{/shop/articles/4151}">Earbuds<a/></td>
<td> 3</td>
<td>63,95&nbsp;EUR</td>
</tr>
<tr>
<th></th>
<th></th>
<th>Position</th>
<th>Preis</th>
</tr>
<tr>
<td></td>
<td></td>
<td>Artikel (Netto)</td>
<td> 120,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Bonuspunkte</td>
<td> 5,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Umsatzsteuer (19%)</td>
<td> 42,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>
<h3>Gesammtpreis</h3>
</td>
<td>
<h3>240,79&nbsp;EUR</h3>
</td>
</tr>
</table>
</div>
<div>
<h2 id="20200101"> Bestellung vom 01.01.2020 </h2>
<div>
<table class="key-value">
<tr>
<th>Lieferstatus</th>
<td><b>Angekommen</b> <br/> 03.01.2020</td>
</tr>
<tr>
<th>Sendeverfolgungsnummer</th>
<td>XE5140684351DE</td>
</tr>
<tr>
<th></th>
<td>
Hans Maier <br/>
Hauptstraße 12<br/>
74880 Musterstadt<br/>
Deutschland <br/>
</td>
</tr>
<tr>
<th>Gutgeschriebene Bonuspunkte</th>
<td>5</td>
</tr>
</table>
</div>
<table>
<tr>
<th>Bild</th>
<th>Name</th>
<th>Menge</th>
<th>Preis pro Artikel (Brutto)</th>
</tr>
<tr>
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-1.jpg}" class="s"/><a></td>
<td><a th:href="@{/shop/articles/4151}"> Billige Kamera<a/></td>
<td> 1</td>
<td>40,50&nbsp;EUR</td>
</tr>
<tr>
<td><a th:href="@{/shop/articles/4151}"><img th:src="@{/img/product-5.jpg}" class="s"/><a></td>
<td><a th:href="@{/shop/articles/4151}">Apfel<a/></td>
<td> 5</td>
<td>1,00&nbsp;EUR</td>
</tr>
<tr>
<th></th>
<th></th>
<th>Position</th>
<th>Preis</th>
</tr>
<tr>
<td></td>
<td></td>
<td>Artikel (Netto)</td>
<td> 20,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Umsatzsteuer (19%)</td>
<td> 5,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Umsatzsteuer (7%)</td>
<td> 2,00&nbsp;EUR</td>
</tr>
<tr>
<td></td>
<td></td>
<td>
<h3>Gesammtpreis</h3>
</td>
<td>
<h3>50,79&nbsp;EUR</h3>
</td>
</tr>
</table>
</div>
</div>
</main>
<footer th:replace="fragments/footer :: footer"></footer>
</body>
</html>

50
supplier/config/mda.json Normal file
View File

@ -0,0 +1,50 @@
{
"id" : "mda",
"name" : "MDA",
"discount" : {
"minimumDailySalesVolumeNetCent": 20,
"percentDiscount": 3
},
"articles": [
{
"title": "MDA Nezyr 7",
"manufacturer": "MDA",
"articleNumber": "n7",
"vatPercent": 19,
"pricePerUnitNet": 29990,
"shouldBeAdvertised": true
},
{
"title": "MDA Nezyr 5",
"manufacturer": "MDA",
"articleNumber": "n5",
"vatPercent": 19,
"pricePerUnitNet": 19700,
"shouldBeAdvertised": true
},
{
"title": "MDA Nezyr 3",
"manufacturer": "MDA",
"articleNumber": "n3",
"vatPercent": 19,
"pricePerUnitNet": 8990,
"shouldBeAdvertised": false
},
{
"title": "MDA Nezyr Threadcracker 3990",
"manufacturer": "MDA",
"articleNumber": "ntc3990",
"vatPercent": 19,
"pricePerUnitNet": 404900,
"shouldBeAdvertised": true
},
{
"title": "MDA Radon RX 5700",
"manufacturer": "MDA",
"articleNumber": "rrx5700",
"vatPercent": 19,
"pricePerUnitNet": 43624,
"shouldBeAdvertised": true
}
]
}

View File

@ -0,0 +1,34 @@
{
"id" : "nanosoft",
"name" : "Nanosoft",
"discount" : {
"minimumDailySalesVolumeNetCent": 50,
"percentDiscount": 0.5
},
"articles": [
{
"title": "Nanosoft Doors 10",
"manufacturer": "Nanosoft",
"articleNumber": "d10",
"vatPercent": 7,
"pricePerUnitNet": 2099,
"shouldBeAdvertised": true
},
{
"title": "Nanosoft Interior Pro 7",
"manufacturer": "Nanosoft",
"articleNumber": "ip7",
"vatPercent": 19,
"pricePerUnitNet": 90780,
"shouldBeAdvertised": false
},
{
"title": "Nanosoft Ybox Two",
"manufacturer": "Nanosoft",
"articleNumber": "ybox2",
"vatPercent": 19,
"pricePerUnitNet": 23500,
"shouldBeAdvertised": true
}
]
}

View File

@ -0,0 +1,42 @@
{
"id" : "outtel",
"name" : "Outtel",
"discount" : {
"minimumDailySalesVolumeNetCent": 20,
"percentDiscount": 1
},
"articles": [
{
"title": "Outtel Core o7",
"manufacturer": "Outtel",
"articleNumber": "o7",
"vatPercent": 19,
"pricePerUnitNet": 40000,
"shouldBeAdvertised": true
},
{
"title": "Outtel Core o5",
"manufacturer": "Outtel",
"articleNumber": "o5",
"vatPercent": 19,
"pricePerUnitNet": 25000,
"shouldBeAdvertised": true
},
{
"title": "Outtel Core o3",
"manufacturer": "Outtel",
"articleNumber": "o3",
"vatPercent": 7,
"pricePerUnitNet": 8000,
"shouldBeAdvertised": false
},
{
"title": "Outtel Core o9",
"manufacturer": "Outtel",
"articleNumber": "o9",
"vatPercent": 19,
"pricePerUnitNet": 55000,
"shouldBeAdvertised": true
}
]
}

50
supplier/config/pear.json Normal file
View File

@ -0,0 +1,50 @@
{
"id" : "pear",
"name" : "Pear",
"discount" : {
"minimumDailySalesVolumeNetCent": 100,
"percentDiscount": 2
},
"articles": [
{
"title": "Pear iMobile 10",
"manufacturer": "Pear",
"articleNumber": "iM10",
"vatPercent": 19,
"pricePerUnitNet": 31500,
"shouldBeAdvertised": true
},
{
"title": "Pear iPlate Plus",
"manufacturer": "Pear",
"articleNumber": "ipp",
"vatPercent": 19,
"pricePerUnitNet": 44900,
"shouldBeAdvertised": true
},
{
"title": "Pear iDonalds 9",
"manufacturer": "Pear",
"articleNumber": "id9",
"vatPercent": 19,
"pricePerUnitNet": 234800,
"shouldBeAdvertised": true
},
{
"title": "Pear GroundPods",
"manufacturer": "Pear",
"articleNumber": "gp",
"vatPercent": 7,
"pricePerUnitNet": 13599,
"shouldBeAdvertised": true
},
{
"title": "Pear Donalsbook Pro",
"manufacturer": "Pear",
"articleNumber": "dbp",
"vatPercent": 7,
"pricePerUnitNet": 145900,
"shouldBeAdvertised": true
}
]
}

View File

@ -0,0 +1,42 @@
{
"id" : "sumsang",
"name" : "Sumsang",
"discount" : {
"minimumDailySalesVolumeNetCent": 300,
"percentDiscount": 2
},
"articles": [
{
"title": "Sumsang Universe S10",
"manufacturer": "Sumsang",
"articleNumber": "us10",
"vatPercent": 19,
"pricePerUnitNet": 59000,
"shouldBeAdvertised": true
},
{
"title": "Sumsang Universe S10e",
"manufacturer": "Sumsang",
"articleNumber": "us10e",
"vatPercent": 19,
"pricePerUnitNet": 70231,
"shouldBeAdvertised": false
},
{
"title": "Sumsang DumbTV",
"manufacturer": "Sumsang",
"articleNumber": "dtv",
"vatPercent": 19,
"pricePerUnitNet": 38395,
"shouldBeAdvertised": true
},
{
"title": "Sumsang UniverseWatch",
"manufacturer": "Sumsang",
"articleNumber": "uw",
"vatPercent": 19,
"pricePerUnitNet": 20494,
"shouldBeAdvertised": true
}
]
}

View File

@ -0,0 +1,58 @@
{
"id" : "techdealer",
"name" : "Tech Dealer",
"discount" : {
"minimumDailySalesVolumeNetCent": 100,
"percentDiscount": 2
},
"articles": [
{
"title": "TROPIC Gehäuselüfter",
"manufacturer": "TROPIC",
"articleNumber": "tgl",
"vatPercent": 19,
"pricePerUnitNet": 459,
"shouldBeAdvertised": true
},
{
"title": "Pirate PC-Netzteil",
"manufacturer": "Pirate",
"articleNumber": "ppcn",
"vatPercent": 19,
"pricePerUnitNet": 9355,
"shouldBeAdvertised": true
},
{
"title": "Pirate Void Elite RGB Wireless Gaming Headset",
"manufacturer": "Pirate",
"articleNumber": "pvergbwgh",
"vatPercent": 7,
"pricePerUnitNet": 10999,
"shouldBeAdvertised": false
},
{
"title": "Aeroheat CYLON PC-Gehäuse",
"manufacturer": "Aeroheat",
"articleNumber": "acpcg",
"vatPercent": 19,
"pricePerUnitNet": 3999,
"shouldBeAdvertised": true
},
{
"title": "Illogitech C270 Webcam",
"manufacturer": "Illogitech",
"articleNumber": "ic270w",
"vatPercent": 19,
"pricePerUnitNet": 3499,
"shouldBeAdvertised": true
},
{
"title": "Illogitech Z607 Surround Sound Lautsprecher",
"manufacturer": "Illogitech",
"articleNumber": "iz607ssl",
"vatPercent": 19,
"pricePerUnitNet": 9495,
"shouldBeAdvertised": false
}
]
}

View File

@ -1,5 +1,9 @@
package org.hso.ecommerce.supplier;
import org.hso.ecommerce.supplier.carrier.Avian;
import org.hso.ecommerce.supplier.carrier.Carrier;
import org.hso.ecommerce.supplier.carrier.Posaidon;
import org.hso.ecommerce.supplier.carrier.Shredder;
import org.hso.ecommerce.supplier.data.Article;
import org.hso.ecommerce.supplier.data.Order;
import org.hso.ecommerce.supplier.data.OrderConfirmation;
@ -19,9 +23,13 @@ import java.util.List;
public class RequestController {
private final HashMap<String, Integer> dailySalesVolumeCent = new HashMap<>();
private final HashMap<String, Supplier> knownSuppliers = new HashMap<>();
private final HashMap<String, Supplier> knownSuppliers = new HashMap<>();
private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
private final Carrier[] carriers = new Carrier[]{
new Avian(), new Posaidon(), new Shredder()
};
@PostConstruct
public void init() throws IOException {
for (Supplier s : ConfigurationReader.read()) {
@ -38,7 +46,7 @@ public class RequestController {
@GetMapping("/{supplier}/")
public Supplier supplier(HttpServletResponse res, @PathVariable("supplier") String supplierName) {
Supplier s = knownSuppliers.get(supplierName);
if(s == null) {
if (s == null) {
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
return s;
@ -47,25 +55,32 @@ public class RequestController {
@PostMapping("/{supplier}/order")
public OrderConfirmation order(HttpServletResponse res, @PathVariable("supplier") String supplierName, @RequestBody Order order) {
Supplier s = knownSuppliers.get(supplierName);
if(s == null) {
if (s == null) {
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
return null;
}
String dateKey = simpleDateFormat.format(new Date());
int dailyVolume = dailySalesVolumeCent.getOrDefault(dateKey,0);
int dailyVolume = dailySalesVolumeCent.getOrDefault(dateKey, 0);
Article a = s.findArticle(order.manufacturer, order.articleNumber);
if(a == null) {
if (a == null) {
res.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return null;
}
int priceNet = a.pricePerUnitNet * order.quantity;
int discount = 0;
if(dailyVolume >= s.discount.minimumDailySalesVolumeNetCent) {
discount = (priceNet * s.discount.percentDiscount) / 100;
int discountableNetAmount = 0;
if (dailyVolume >= s.discount.minimumDailySalesVolumeNetCent) {
// grant discount on the full price
discountableNetAmount = priceNet;
} else if (dailyVolume + priceNet > s.discount.minimumDailySalesVolumeNetCent) {
// grant partial discount
discountableNetAmount = dailyVolume + priceNet - s.discount.minimumDailySalesVolumeNetCent;
}
int discount = (discountableNetAmount * s.discount.percentDiscount) / 100;
Carrier selectedCarrier = carriers[Math.abs((supplierName + java.time.LocalDate.now()).hashCode()) % carriers.length];
OrderConfirmation confirmation = new OrderConfirmation();
confirmation.articleNumber = order.articleNumber;
@ -74,6 +89,9 @@ public class RequestController {
confirmation.manufacturer = a.manufacturer;
confirmation.quantity = order.quantity;
confirmation.totalPriceNetCharged = priceNet - discount;
confirmation.carrier = selectedCarrier.getName();
confirmation.trackingId = selectedCarrier.generateTrackingId();
confirmation.estimatedArrival = selectedCarrier.arrivalEstimate();
if (confirmation.totalPriceNetCharged > order.maxTotalPriceCentNet) {
res.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);

View File

@ -0,0 +1,28 @@
package org.hso.ecommerce.supplier.carrier;
import java.time.LocalDateTime;
import java.util.Random;
public class Avian implements Carrier {
@Override
public String getName() {
return "Avian Carriers";
}
@Override
public String generateTrackingId() {
Random rnd = new Random();
return "2001-"
+ Integer.toHexString(rnd.nextInt(0xFFFF))
+ "--"
+ Integer.toHexString(rnd.nextInt(0xFFFF))
+ "-"
+ Integer.toHexString(rnd.nextInt(0xFFFF));
}
@Override
public LocalDateTime arrivalEstimate() {
return LocalDateTime.now().plusHours(8);
}
}

View File

@ -0,0 +1,12 @@
package org.hso.ecommerce.supplier.carrier;
import java.time.LocalDateTime;
public interface Carrier {
public String getName();
public String generateTrackingId();
public LocalDateTime arrivalEstimate();
}

View File

@ -0,0 +1,26 @@
package org.hso.ecommerce.supplier.carrier;
import java.time.LocalDateTime;
import java.util.Random;
public class Posaidon implements Carrier {
@Override
public String getName() {
return "Poseidon Inc.";
}
@Override
public String generateTrackingId() {
Random rnd = new Random();
return "WAT"
+ Integer.toString(rnd.nextInt(Short.MAX_VALUE))
+ "3"
+ Integer.toString(rnd.nextInt(Short.MAX_VALUE))
+ "R";
}
@Override
public LocalDateTime arrivalEstimate() {
return LocalDateTime.now().plusHours(50);
}
}

View File

@ -0,0 +1,31 @@
package org.hso.ecommerce.supplier.carrier;
import java.time.LocalDateTime;
import java.util.Random;
public class Shredder implements Carrier {
private Random rnd = new Random();
@Override
public String getName() {
return "Schree & Derr";
}
@Override
public String generateTrackingId() {
return "O" + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + d() + "0";
}
@Override
public LocalDateTime arrivalEstimate() {
return LocalDateTime.now().plusHours(22);
}
/**
* @return a random digit followed by a dash.
*/
private String d() {
return Integer.toString(rnd.nextInt(9)) + "-";
}
}

View File

@ -1,5 +1,7 @@
package org.hso.ecommerce.supplier.data;
import java.time.LocalDateTime;
public class OrderConfirmation {
public String manufacturer;
public String articleNumber;
@ -9,4 +11,8 @@ public class OrderConfirmation {
public int pricePerUnitNetCent;
public int discountNetCent;
public int totalPriceNetCharged;
public String carrier;
public String trackingId;
public LocalDateTime estimatedArrival;
}

View File

@ -5,3 +5,5 @@ e-commerce.db
./e-commerce.iml
./e-commerce.ipr
./e-commerce.iws
config.yml

View File

@ -28,6 +28,7 @@ dependencies {
implementation 'com.github.gwenn:sqlite-dialect:0.1.0'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'org.xerial:sqlite-jdbc:3.31.1'
implementation 'org.yaml:snakeyaml:1.26'
testCompile("org.springframework.boot:spring-boot-starter-test")
}

0
prototype/gradlew → web_backend/gradlew vendored Normal file → Executable file
View File

View File

@ -10,6 +10,7 @@ public class CreateBookingAction {
public CreateBookingAction(BookingAccountEntry source, BookingAccountEntry destination, BookingReason reason, int amountCent) {
booking = new Booking();
booking.created = new java.sql.Timestamp(System.currentTimeMillis());
booking.reason = reason;
booking.amountCent = amountCent;

View File

@ -1,8 +1,5 @@
package org.hso.ecommerce.action.cronjob;
import java.sql.Timestamp;
import java.util.HashMap;
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.Offer;
import org.hso.ecommerce.api.SupplierService;
@ -14,6 +11,9 @@ import org.hso.ecommerce.entities.supplier.SupplierOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Timestamp;
import java.util.HashMap;
public class ReorderAction {
private static final Logger log = LoggerFactory.getLogger(ReorderAction.class);
@ -102,6 +102,10 @@ public class ReorderAction {
createdOrder.numberOfUnits = confirm.quantity;
createdOrder.pricePerUnitNetCent = confirm.pricePerUnitNetCent;
createdOrder.totalPriceNet = confirm.totalPriceNetCharged;
createdOrder.carrier = confirm.carrier;
createdOrder.trackingId = confirm.trackingId;
createdOrder.estimatedArrival = Timestamp.valueOf(confirm.estimatedArrival);
return createdOrder;
}
}

View File

@ -30,9 +30,10 @@ public class UpdateOffersAction {
public List<ArticleOffer> finish() {
HashMap<ArticleIdentifier, ArticleOffer> availableOffers = mapOffers();
// Reset all advertise-flags first. They are set again below.
// Reset all advertise-flags and supplier relations first. They are set again below.
for (ArticleOffer offer : availableOffers.values()) {
offer.shouldBeAdvertised = false;
offer.cheapestSupplier = null;
}
for (Entry<ArticleIdentifier, Offer> cheapestOffer : cheapestOffer.entrySet()) {
@ -47,7 +48,10 @@ public class UpdateOffersAction {
}
Article currentOfferedArticle = cheapestOffer.getValue().apiSupplier.findArticle(manufacturer,
articleNumber);
currentOffer.title = currentOfferedArticle.title;
currentOffer.vatPercent = currentOfferedArticle.vatPercent;
currentOffer.cheapestSupplier = cheapestOffer.getValue().dbSupplier;
currentOffer.pricePerUnitNet = currentOfferedArticle.pricePerUnitNet;
// Set advertise-flag if any supplier wants it to be set
if (currentOfferedArticle.shouldBeAdvertised) {

View File

@ -13,6 +13,7 @@ import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@ -74,9 +75,15 @@ public class CreateOrderAction {
CustomerPayment payment = createPayment();
List<Booking> bookingList = new ArrayList<>();
bookingList.add(new CreateBookingAction(latestUserBooking, latestMainBooking, new BookingReason(order), order.totalGrossCent).finish());
bookingList.add(new CreateBookingAction(null, latestUserBooking, new BookingReason(payment), order.totalGrossCent).finish());
bookingList.add(new CreateBookingAction(latestMainBooking, latestVatBooking, new BookingReason(order), order.totalVatCent).finish());
Booking purchaseBooking = new CreateBookingAction(
latestUserBooking, latestMainBooking, new BookingReason(order), order.totalGrossCent).finish();
Booking paymentBooking = new CreateBookingAction(
null, purchaseBooking.source /* userAccount */, new BookingReason(payment), order.totalGrossCent).finish();
Booking vatBooking = new CreateBookingAction(
purchaseBooking.destination /* mainAccount */, latestVatBooking, new BookingReason(order), order.totalVatCent).finish();
bookingList.add(purchaseBooking);
bookingList.add(paymentBooking);
bookingList.add(vatBooking);
WarehouseBooking warehouseBooking = createWarehouseBooking(order);
@ -95,7 +102,14 @@ public class CreateOrderAction {
for (OrderItem item : orderItems) {
int needed = item.quantity;
// Sort for most empty slot first;
item.availableSlots.sort(Comparator.comparingInt(a -> a.newSumSlot));
for (WarehouseBookingPositionSlotEntry slot : item.availableSlots) {
if (slot.newSumSlot == 0) {
continue;
}
int remove = Math.min(slot.newSumSlot, needed);
needed -= remove;
@ -103,7 +117,7 @@ public class CreateOrderAction {
bookingPosition.article = item.article;
bookingPosition.amount = -remove;
bookingPosition.slotEntry = slot.copyAddAmount(-remove);
bookingPosition.slotEntry = slot.copyAddAmount(-remove, item.article);
bookingPosition.booking = booking;
booking.positions.add(bookingPosition);

View File

@ -0,0 +1,16 @@
package org.hso.ecommerce.action.shop;
import org.hso.ecommerce.api.RestServiceForDelivery;
import org.hso.ecommerce.entities.shop.CustomerOrder;
import org.springframework.web.client.ResourceAccessException;
import java.sql.Timestamp;
import java.util.Date;
public class EnableTrackingAction {
public static void addTrackingInfo(RestServiceForDelivery deliveryService, CustomerOrder customerOrder) throws ResourceAccessException {
customerOrder.inDeliverySince = new Timestamp(new Date().getTime());
customerOrder.trackingId = deliveryService.getDeliveryID(customerOrder);
}
}

View File

@ -0,0 +1,40 @@
package org.hso.ecommerce.action.shop;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SearchByTermAction {
public static List<Article> searchByTerm(String sourceTerm, ArticleRepository repository) {
List<String> terms = Arrays.asList(sourceTerm.split(" "));
List<Article> resultArticles = new ArrayList<>();
terms.forEach(term -> {
List<Article> titleArticles = repository.getArticlesByTermInTitle(term); //search in Title
titleArticles.forEach(article -> {
if(!resultArticles.contains(article)){
resultArticles.add(article);
}
});
});
terms.forEach(term -> {
List<Article> descArticles = repository.getArticlesByTermInDescription(term); //search by Term
descArticles.forEach(article -> {
if(!resultArticles.contains(article)){
resultArticles.add(article);
}
});
});
return resultArticles;
}
}

View File

@ -0,0 +1,48 @@
package org.hso.ecommerce.action.user;
import org.hso.ecommerce.api.RestServiceForDelivery;
import org.hso.ecommerce.entities.shop.CustomerOrder;
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
import org.hso.ecommerce.uimodel.DeliveryData;
import org.hso.ecommerce.uimodel.DeliveryDataEnum;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class CreateDeliveryData {
public static DeliveryData getDeliveryDataFromCustomerOrder(CustomerOrder customerOrder, CustomerOrderRepository customerOrderRepository, RestServiceForDelivery restServiceForDelivery)
{
if(customerOrder.trackingId == null)
return new DeliveryData("", "", DeliveryDataEnum.NO_TRACKING_ID);
if(customerOrder.deliveredAt == null)
{
DeliveryData deliveryData = restServiceForDelivery.getDeliveryData(customerOrder.trackingId);
if(deliveryData.isDelivered())
{
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MM-yyyy");
try {
calendar.setTime(simpleDateFormat.parse(deliveryData.getEstimatedArrival()));
} catch (ParseException e) {
e.printStackTrace();
}
customerOrder.deliveredAt = new Timestamp(calendar.getTimeInMillis());
customerOrderRepository.save(customerOrder);
}
return deliveryData;
}
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
return new DeliveryData("Lieferung erfolgreich", formatter.format(customerOrder.deliveredAt), DeliveryDataEnum.OK);
}
}

View File

@ -0,0 +1,83 @@
package org.hso.ecommerce.action.user;
import org.hso.ecommerce.entities.booking.PaymentMethod;
import org.hso.ecommerce.entities.user.User;
import org.hso.ecommerce.repos.user.UserRepository;
public class UpdateUserSettingsAction {
private User user;
private UserRepository repository;
public UpdateUserSettingsAction(User user, UserRepository repository) {
this.user = user;
this.repository = repository;
}
public UpdateResult updateEmail(String newMail) {
UpdateResult result = new UpdateResult(false);
if (!newMail.contains("@")) {
result.errorString = "Ändern der Email-Addresse nicht möglich. Bitte versuchen Sie es erneut.";
} else {
this.user.email = newMail;
this.repository.save(this.user);
result.updated = true;
}
return result;
}
public UpdateResult updatePassword(String oldPassword, String password1, String password2) {
UpdateResult result = new UpdateResult(false);
if (this.user.validatePassword(oldPassword)) {
if (password1.equals(password2)) {
if (!password1.equals(oldPassword)) {
this.user.setPassword(password1);
this.repository.save(this.user);
result.updated = true;
} else {
result.errorString = "Das neue Passwort entspricht dem alten Passwort.";
}
} else {
result.errorString = "Die beiden neuen Passwörter stimmen nicht überein. Bitte versuchen Sie es erneut.";
}
} else {
result.errorString = "Das eingegebene alte Passwort stimmt nicht mit dem momentan gespeicherten Passwort überein. Bitte versuchen Sie es erneut.";
}
return result;
}
public UpdateResult updateShippingInfo(String salutation, String name, String address) {
this.user.salutation = salutation;
this.user.defaultDeliveryAddress.name = name;
this.user.defaultDeliveryAddress.addressString = address;
this.repository.save(this.user);
return new UpdateResult(true);
}
public UpdateResult updatePaymentInfo(String creditCardNumber) {
UpdateResult result = new UpdateResult(false);
if (creditCardNumber.matches("[0-9]+")) {
this.user.defaultPayment = PaymentMethod.fromCreditCardNumber(creditCardNumber);
this.repository.save(this.user);
result.updated = true;
} else {
result.errorString = "Kreditkartennummer darf nur Zahlen enthalten. Bitte versuchen Sie es erneut.";
}
return result;
}
public class UpdateResult {
public boolean updated; //if true worked, if false not worked
public String errorString;
public UpdateResult(boolean updated, String errorString) {
this.updated = updated;
this.errorString = errorString;
}
public UpdateResult(boolean updated) {
this.updated = updated;
this.errorString = "";
}
}
}

View File

@ -0,0 +1,73 @@
package org.hso.ecommerce.action.warehouse;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
import java.util.HashSet;
import java.util.List;
public class CalculateWarehouseStatsAction {
private List<WarehouseBookingPositionSlotEntry> entryList;
public CalculateWarehouseStatsAction(List<WarehouseBookingPositionSlotEntry> everyCurrentEntry) {
this.entryList = everyCurrentEntry;
}
public WarehouseStats finish() {
int numArticles = calculateNumArticles();
double efficiency = calculateEfficiency();
double ratioUsedSlots = calculateRatioSlotsUsed();
return new WarehouseStats(numArticles, efficiency, ratioUsedSlots);
}
private double calculateRatioSlotsUsed() {
int used = 0;
for (WarehouseBookingPositionSlotEntry entry : entryList) {
if (entry.newSumSlot > 0) {
used++;
}
}
return ((double) used) / entryList.size();
}
private double calculateEfficiency() {
double e = 0;
for (WarehouseBookingPositionSlotEntry entry : entryList) {
if (entry.newSumSlot > 0) {
e += entry.newSumSlot / (double) entry.article.warehouseUnitsPerSlot;
} else {
e += 0;
}
}
return e / entryList.size();
}
private int calculateNumArticles() {
HashSet<Long> articleIds = new HashSet<>();
for (WarehouseBookingPositionSlotEntry entry : entryList) {
if (entry.newSumSlot > 0) {
articleIds.add(entry.article.id);
}
}
return articleIds.size();
}
public static class WarehouseStats {
public int numArticles;
public double efficiency;
public double ratioUsedSlots;
WarehouseStats(int numArticles, double efficiency, double ratioUsedSlots) {
this.numArticles = numArticles;
this.efficiency = efficiency;
this.ratioUsedSlots = ratioUsedSlots;
}
}
}

View File

@ -0,0 +1,92 @@
package org.hso.ecommerce.action.warehouse;
import org.hso.ecommerce.entities.booking.BookingReason;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Optional;
public class CreateManuelBookingAction {
private Article article;
private int amount;
private Optional<WarehouseBookingPositionSlotEntry> source;
private Optional<WarehouseBookingPositionSlotEntry> destination;
private String reason;
public CreateManuelBookingAction(Article article, int amount, Optional<WarehouseBookingPositionSlotEntry> source, Optional<WarehouseBookingPositionSlotEntry> destination, String reason) {
this.article = article;
this.amount = amount;
this.source = source;
this.destination = destination;
this.reason = reason;
}
public WarehouseBooking finish() throws ArticleSlotConstraintFailedException {
WarehouseBooking booking = new WarehouseBooking();
booking.created = new Timestamp(new Date().getTime());
booking.reason = new BookingReason(reason);
if (source.isPresent()) {
if (source.get().article.id != article.id) {
throw new ArticleSlotConstraintArticleTypeFailedException();
}
WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
bookingPosition.booking = booking;
bookingPosition.article = article;
bookingPosition.amount = -amount;
bookingPosition.slotEntry = source.get().copyAddAmount(-amount, article);
if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) {
throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds.");
}
booking.positions.add(bookingPosition);
}
if (destination.isPresent()) {
if (destination.get().article.id != article.id && destination.get().newSumSlot > 0) {
throw new ArticleSlotConstraintArticleTypeFailedException();
}
WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
bookingPosition.booking = booking;
bookingPosition.article = article;
bookingPosition.amount = amount;
bookingPosition.slotEntry = destination.get().copyAddAmount(amount, article);
if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) {
throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds.");
}
booking.positions.add(bookingPosition);
}
return booking;
}
public static class ArticleSlotConstraintFailedException extends Exception {
public ArticleSlotConstraintFailedException(String s) {
super(s);
}
public ArticleSlotConstraintFailedException() {
super("The quantity of article can only be set in bounds.");
}
}
public static class ArticleSlotConstraintArticleTypeFailedException extends ArticleSlotConstraintFailedException {
public ArticleSlotConstraintArticleTypeFailedException() {
super("The Article in the slot entry does not match.");
}
}
}

View File

@ -0,0 +1,103 @@
package org.hso.ecommerce.action.warehouse;
import org.hso.ecommerce.entities.booking.BookingReason;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.supplier.SupplierOrder;
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class SupplierOrderArrivedAction {
private final Article article;
private final ArrayList<WarehouseBookingPositionSlotEntry> warehouseCandidates;
private final SupplierOrder order;
public SupplierOrderArrivedAction(List<WarehouseBookingPositionSlotEntry> warehouseCandidates, SupplierOrder order, Article article) {
this.warehouseCandidates = new ArrayList<>(warehouseCandidates);
this.order = order;
this.article = article;
}
public Result finish() throws NoSpaceInWarehouseException {
// Sort for most filled slot first;
warehouseCandidates.sort((b, a) -> Integer.compare(a.newSumSlot, b.newSumSlot));
int needed = order.numberOfUnits;
WarehouseBooking booking = new WarehouseBooking();
booking.created = new Timestamp(new Date().getTime());
booking.reason = new BookingReason(order);
for (WarehouseBookingPositionSlotEntry entry : warehouseCandidates) {
int canBeAdded = article.warehouseUnitsPerSlot - entry.newSumSlot;
if (canBeAdded == 0) {
// this slot is full, skip
continue;
}
int willBeAdded = Math.min(canBeAdded, needed);
needed -= willBeAdded;
WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
bookingPosition.article = article;
bookingPosition.amount = willBeAdded;
bookingPosition.slotEntry = entry.copyAddAmount(willBeAdded, article);
bookingPosition.booking = booking;
booking.positions.add(bookingPosition);
if (needed == 0) {
break;
}
}
if (needed > 0) {
throw new NoSpaceInWarehouseException(article);
}
order.delivered = new Timestamp(new Date().getTime());
return new Result(order, booking);
}
public static class Result extends Exception {
private final SupplierOrder order;
private final WarehouseBooking booking;
public Result(SupplierOrder order, WarehouseBooking booking) {
this.order = order;
this.booking = booking;
}
public SupplierOrder getOrder() {
return order;
}
public WarehouseBooking getBooking() {
return booking;
}
}
public static class NoSpaceInWarehouseException extends Exception {
private Article article;
public NoSpaceInWarehouseException(Article article) {
super("The quantity of article '" + article.title + "' does not fit in warehouse.");
this.article = article;
}
public Article getArticle() {
return article;
}
}
}

View File

@ -0,0 +1,83 @@
package org.hso.ecommerce.api;
import org.hso.ecommerce.app.config.AppSettings;
import org.hso.ecommerce.entities.shop.CustomerOrder;
import org.hso.ecommerce.uimodel.DeliveryData;
import org.hso.ecommerce.uimodel.DeliveryDataEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.HashMap;
import java.util.Map;
@Service
public class RestServiceForDelivery {
@Autowired
private final RestTemplateBuilder restTemplateBuilder = null;
@Autowired
private final AppSettings settings = null;
private String getDeliveryEndpoint() {
return settings.getParcelServiceApiURL();
}
public String getDeliveryID(CustomerOrder customerOrder) throws ResourceAccessException {
String url = getDeliveryEndpoint() + "/newDelivery";
RestTemplate restTemplate = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Map<String, String> requestBody = new HashMap<>();
requestBody.put("name", customerOrder.destination.name);
requestBody.put("address", customerOrder.destination.addressString);
HttpEntity<Map<String, String>> entity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
return response.getBody();
} else {
throw new ResourceAccessException("Http Status wrong");
}
}
public DeliveryData getDeliveryData(String trackingID) {
String url = getDeliveryEndpoint() + "/status";
RestTemplate restTemplate = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParam("trackingID", trackingID);
HttpEntity<?> entity = new HttpEntity<>(headers);
ResponseEntity<DeliveryData> response;
try {
response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, entity, DeliveryData.class);
if (response.getStatusCode() == HttpStatus.OK) {
return response.getBody();
} else {
return new DeliveryData("", "", DeliveryDataEnum.NO_DATA);
}
} catch (Exception e) {
return new DeliveryData("", "", DeliveryDataEnum.NO_DATA);
}
}
}

View File

@ -1,5 +1,7 @@
package org.hso.ecommerce.api.data;
import java.time.LocalDateTime;
public class OrderConfirmation {
public String manufacturer;
public String articleNumber;
@ -9,4 +11,8 @@ public class OrderConfirmation {
public int pricePerUnitNetCent;
public int discountNetCent;
public int totalPriceNetCharged;
public String carrier;
public String trackingId;
public LocalDateTime estimatedArrival;
}

View File

@ -13,6 +13,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

View File

@ -0,0 +1,161 @@
package org.hso.ecommerce.app.config;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import org.hso.ecommerce.app.config.YAMLData.Address;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import javax.annotation.PostConstruct;
@Component("appSettings")
public class AppSettings {
private YAMLData data;
private final String configFile = "config.yml";
private String installationName;
private String companyName;
private Address companyAddress;
private int numberOfStorageSpaces;
private List<YAMLData.Supplier> suppliers;
private String parcelServiceName;
private String parcelServiceApiURL;
/**
* on initialization read the config and store the data in static objects
*/
@PostConstruct
public void init() {
data = readConfig();
installationName = data.getInstallationName();
companyName = data.getCompanyName();
companyAddress = data.getCompanyAddress();
numberOfStorageSpaces = data.getNumberOfStorageSpaces();
suppliers = data.getSuppliers();
parcelServiceName = data.getParcelServiceName();
parcelServiceApiURL = data.getParcelServiceApiURL();
System.out.println("Initialised Settings!");
}
/**
* write the default config file
*/
public void writeDefaultConfig() {
YAMLData data = new YAMLData();
data.setInstallationName("eCommerce");
data.setCompanyName("eCommerce Shop UG");
data.setCompanyAddress(new Address(
"Musterstraße",
"1",
"12345",
"Musterstadt",
"Germany"
));
data.setNumberOfStorageSpaces(128);
List<YAMLData.Supplier> suppliers = new ArrayList<>();
suppliers.add(new YAMLData.Supplier(
"Bank of Chees",
"d41d8cd98f00b204e9800998ecf8427e",
"http://[::1]:8081/bank/",
4,
new Address(
"Musterstraße",
"2",
"12345",
"Musterstadt",
"Germany"
)
));
suppliers.add(new YAMLData.Supplier(
"MDA",
"18a17da5bac1cf00551b08c3e98720f5",
"http://[::1]:8081/mda/",
5,
new Address(
"Musterstraße",
"3",
"12345",
"Musterstadt",
"Germany"
)
));
data.setSuppliers(suppliers);
data.setParcelServiceName("Parcel Service");
data.setParcelServiceApiURL("http://[::1]:8082/");
try (FileWriter writer = new FileWriter("./" + configFile)) {
Yaml yaml = new Yaml();
yaml.dump(data, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* read a config file named "eCommerce_config.yml" from the applications root directory
* @return the settings as YAMLData object
*/
public YAMLData readConfig() {
YAMLData data = new YAMLData();
File file = new File("./" + configFile);
if (!file.exists()) {
writeDefaultConfig();
}
try (InputStream inputStream = new FileInputStream("./" + configFile)) {
Yaml yaml = new Yaml(new Constructor(YAMLData.class));
data = yaml.load(inputStream);
} catch (FileNotFoundException e) {
System.err.println("The file \"" + configFile + "\" has not been found, please create a valid Configuration file.");
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
return data;
}
public YAMLData getData() {
return data;
}
public String getInstallationName() {
return installationName;
}
public String getCompanyName() {
return companyName;
}
public Address getCompanyAddress() {
return companyAddress;
}
public int getNumberOfStorageSpaces() {
return numberOfStorageSpaces;
}
public List<YAMLData.Supplier> getSuppliers() {
return suppliers;
}
public String getParcelServiceName() {
return parcelServiceName;
}
public String getParcelServiceApiURL() {
return parcelServiceApiURL;
}
}

View File

@ -0,0 +1,183 @@
package org.hso.ecommerce.app.config;
import java.util.List;
public class YAMLData {
private String installationName;
private String companyName;
private Address companyAddress;
private int numberOfStorageSpaces;
private List<Supplier> suppliers;
private String parcelServiceName;
private String parcelServiceApiURL;
public String getInstallationName() {
return installationName;
}
public void setInstallationName(String installationName) {
this.installationName = installationName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Address getCompanyAddress() {
return companyAddress;
}
public void setCompanyAddress(Address companyAddress) {
this.companyAddress = companyAddress;
}
public int getNumberOfStorageSpaces() {
return numberOfStorageSpaces;
}
public void setNumberOfStorageSpaces(int numberOfStorageSpaces) {
this.numberOfStorageSpaces = numberOfStorageSpaces;
}
public List<Supplier> getSuppliers() {
return suppliers;
}
public void setSuppliers(List<Supplier> suppliers) {
this.suppliers = suppliers;
}
public String getParcelServiceName() {
return parcelServiceName;
}
public void setParcelServiceName(String parcelServiceName) {
this.parcelServiceName = parcelServiceName;
}
public String getParcelServiceApiURL() {
return parcelServiceApiURL;
}
public void setParcelServiceApiURL(String parcelServiceApiURL) {
this.parcelServiceApiURL = parcelServiceApiURL;
}
public static class Address {
public String streetName;
public String houseNumber;
public String zipCode;
public String cityName;
public String countryName;
public Address() {
// needed by snakeyaml
}
public Address(String streetName, String houseNumber, String zipCode, String cityName, String countryName) {
this.streetName = streetName;
this.houseNumber = houseNumber;
this.zipCode = zipCode;
this.cityName = cityName;
this.countryName = countryName;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public String getHouseNumber() {
return houseNumber;
}
public void setHouseNumber(String houseNumber) {
this.houseNumber = houseNumber;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
public static class Supplier {
public String name;
public String id;
public String apiURL;
public int deliveryTime;
public Address companyAddress;
public Supplier() {
// needed by snakeyaml
}
public Supplier(String name, String id, String apiURL, int deliveryTime, Address companyAddress) {
this.name = name;
this.id = id;
this.apiURL = apiURL;
this.deliveryTime = deliveryTime;
this.companyAddress = companyAddress;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getApiURL() {
return apiURL;
}
public void setApiURL(String apiURL) {
this.apiURL = apiURL;
}
public int getDeliveryTime() {
return deliveryTime;
}
public void setDeliveryTime(int deliveryTime) {
this.deliveryTime = deliveryTime;
}
public Address getCompanyAddress() {
return companyAddress;
}
public void setCompanyAddress(Address companyAddress) {
this.companyAddress = companyAddress;
}
}
}

View File

@ -0,0 +1,36 @@
package org.hso.ecommerce.components;
import org.hso.ecommerce.entities.shop.Address;
import org.hso.ecommerce.entities.user.User;
import org.hso.ecommerce.repos.user.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.sql.Timestamp;
import java.util.Optional;
@Component
public class AdminInitializer {
@Autowired
private final UserRepository userRepository = null;
@PostConstruct
public void init() {
Optional<Integer> numberOfEmployees = userRepository.numberOfEmployees();
if (numberOfEmployees.orElse(0) == 0) {
// create first admin user
User firstAdmin = new User();
firstAdmin.created = new Timestamp(System.currentTimeMillis());
firstAdmin.defaultDeliveryAddress = new Address();
firstAdmin.defaultDeliveryAddress.name = "admin";
firstAdmin.defaultPayment = null;
firstAdmin.email = "admin";
firstAdmin.isActive = true;
firstAdmin.isEmployee = true;
firstAdmin.setPassword("admin");
userRepository.save(firstAdmin); //save to DB
}
}
}

View File

@ -1,5 +1,6 @@
package org.hso.ecommerce.components;
import org.hso.ecommerce.app.config.AppSettings;
import org.hso.ecommerce.entities.warehouse.Slot;
import org.hso.ecommerce.repos.warehouse.SlotRepository;
import org.springframework.beans.factory.annotation.Autowired;
@ -10,14 +11,16 @@ import javax.annotation.PostConstruct;
@Component
public class SlotInitializer {
@Autowired
private final SlotRepository slotRepository = null;
@Autowired
private final SlotRepository slotRepository = null;
// TODO: use values form cfg.
private final int NUM_SLOTS = 50;
@Autowired
private final AppSettings appSettings = null;
@PostConstruct
public void init() {
int NUM_SLOTS = appSettings.getNumberOfStorageSpaces();
for (int i = 1; i <= NUM_SLOTS; i++) {
if (!slotRepository.findBySlotNum(i).isPresent()) {
Slot slotAdded = new Slot();

View File

@ -0,0 +1,42 @@
package org.hso.ecommerce.components;
import org.hso.ecommerce.app.config.AppSettings;
import org.hso.ecommerce.app.config.YAMLData;
import org.hso.ecommerce.entities.supplier.Supplier;
import org.hso.ecommerce.repos.supplier.SupplierRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Optional;
@Component
public class SupplierInitializer {
@Autowired
private final SupplierRepository supplierRepository = null;
@Autowired
private final AppSettings appSettings = null;
@PostConstruct
public void init() {
for (YAMLData.Supplier cfg : appSettings.getSuppliers()) {
Optional<Supplier> sup = supplierRepository.findByUuid(cfg.id);
Supplier supplier;
if (sup.isPresent()) {
supplier = sup.get();
supplier.name = cfg.name;
supplier.apiUrl = cfg.apiURL;
} else {
supplier = new Supplier();
supplier.uuid = cfg.id;
supplier.apiUrl = cfg.apiURL;
supplier.name = cfg.name;
}
supplierRepository.save(supplier);
}
}
}

Some files were not shown because too many files have changed in this diff Show More