Compare commits
	
		
			2 Commits
		
	
	
		
			9211d1f9b4
			...
			73bebf0aec
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 73bebf0aec | ||
|   | 8fda78c466 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -5,3 +5,4 @@ elm-stuff | |||||||
| static/jon.js | static/jon.js | ||||||
| __pycache__ | __pycache__ | ||||||
| *.swp | *.swp | ||||||
|  | py/jon/config.json | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| import inspect | import inspect | ||||||
|  | import json | ||||||
| 
 | 
 | ||||||
| from flask import Flask, render_template | from flask import Flask, render_template | ||||||
| 
 | 
 | ||||||
| @ -13,9 +14,10 @@ from . import ( | |||||||
| 
 | 
 | ||||||
| def create_app(): | def create_app(): | ||||||
|     app = Flask(__name__) |     app = Flask(__name__) | ||||||
|     app.config.from_mapping( |     app.config.from_file("default-config.json", load=json.load) | ||||||
|         SECRET_KEY="dev" |     # You don't need a config.json. If you don't provide one, default-config.json | ||||||
|     ) |     # is used. | ||||||
|  |     app.config.from_file("config.json", load=json.load, silent=True) | ||||||
| 
 | 
 | ||||||
|     db.init_app(app) |     db.init_app(app) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import psycopg2 | import psycopg2 | ||||||
| 
 | 
 | ||||||
| from flask import g | from flask import current_app, g | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from psycopg2.extras import RealDictCursor | from psycopg2.extras import RealDictCursor | ||||||
| 
 | 
 | ||||||
| @ -9,7 +9,7 @@ def get_db(): | |||||||
|     if "db" not in g: |     if "db" not in g: | ||||||
|         # TODO: Make this configurable and use a default that works |         # TODO: Make this configurable and use a default that works | ||||||
|         # on the pool computers. |         # on the pool computers. | ||||||
|         g.db = psycopg2.connect("host=localhost dbname=garfield") |         g.db = psycopg2.connect(current_app.config["DB_CONNECTION_STRING"]) | ||||||
|         run_query_on(g.db, "add_views.sql", None) |         run_query_on(g.db, "add_views.sql", None) | ||||||
| 
 | 
 | ||||||
|     return g.db |     return g.db | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								py/jon/db/transfer_items.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								py/jon/db/transfer_items.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | INSERT INTO garfield.inventory_correction (item_id, delta, correction_comment) | ||||||
|  | VALUES (%(from_item_id)s, -%(amount)s, CONCAT('Umbuchung auf ', %(to_item_id)s)); | ||||||
|  | 
 | ||||||
|  | INSERT INTO garfield.inventory_correction (item_id, delta, correction_comment) | ||||||
|  | VALUES (%(to_item_id)s, %(amount)s, CONCAT('Umbuchung von ', %(from_item_id)s)); | ||||||
							
								
								
									
										4
									
								
								py/jon/default-config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								py/jon/default-config.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | { | ||||||
|  |   "SECRET_KEY": "dev", | ||||||
|  |   "DB_CONNECTION_STRING": "host=fsmi-db dbname=garfield" | ||||||
|  | } | ||||||
| @ -80,3 +80,28 @@ def create_correction(): | |||||||
|     db.get_db().commit() |     db.get_db().commit() | ||||||
| 
 | 
 | ||||||
|     return redirect(request.referrer) |     return redirect(request.referrer) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @bp.post("/transfer") | ||||||
|  | def transfer_items(): | ||||||
|  |     try: | ||||||
|  |         from_item_id = int(request.form.get("from_item_id")) | ||||||
|  |         to_item_id = int(request.form.get("to_item_id")) | ||||||
|  |         amount = int(request.form.get("amount")) | ||||||
|  |     except: | ||||||
|  |         return "Incomplete or mistyped form", 400 | ||||||
|  | 
 | ||||||
|  |     if amount == 0: | ||||||
|  |         return "Amount may not be 0", 400 | ||||||
|  | 
 | ||||||
|  |     if from_item_id == to_item_id: | ||||||
|  |         return "Transfers must be between different items", 400 | ||||||
|  | 
 | ||||||
|  |     db.run_query("transfer_items.sql", { | ||||||
|  |         "from_item_id": from_item_id, | ||||||
|  |         "to_item_id": to_item_id, | ||||||
|  |         "amount": amount | ||||||
|  |     }) | ||||||
|  |     db.get_db().commit() | ||||||
|  | 
 | ||||||
|  |     return redirect(request.referrer) | ||||||
|  | |||||||
| @ -91,6 +91,13 @@ | |||||||
|         </ul> |         </ul> | ||||||
|       </nav> |       </nav> | ||||||
| 
 | 
 | ||||||
|  |       {% if config.DEBUG %} | ||||||
|  |       <details> | ||||||
|  |         <summary><code>config</code></summary> | ||||||
|  |         <pre>{% for key, value in config.items() %}{{ key }} = {{ value }} | ||||||
|  | {% endfor %}</pre> | ||||||
|  |       </details> | ||||||
|  |       {% endif %} | ||||||
|     </header> |     </header> | ||||||
| 
 | 
 | ||||||
|     <main> |     <main> | ||||||
|  | |||||||
| @ -22,8 +22,7 @@ | |||||||
|       <th class="--align-left">Einkaufspreis (Netto)</th> |       <th class="--align-left">Einkaufspreis (Netto)</th> | ||||||
|       <td>{{ format_currency(item.unit_price) }}</td> |       <td>{{ format_currency(item.unit_price) }}</td> | ||||||
|     </tr> |     </tr> | ||||||
|     <tr> |     <tr> <th class="--align-left">Kaufdatum</th> | ||||||
|       <th class="--align-left">Kaufdatum</th> |  | ||||||
|       <td>{{ format_date(item.bought) }}</td> |       <td>{{ format_date(item.bought) }}</td> | ||||||
|     </tr> |     </tr> | ||||||
|     <tr> |     <tr> | ||||||
| @ -121,25 +120,33 @@ | |||||||
|       <th title="Aktive Snackeinträge">AS</th> |       <th title="Aktive Snackeinträge">AS</th> | ||||||
|       <th>Aktiv?</th> |       <th>Aktiv?</th> | ||||||
|     </tr> |     </tr> | ||||||
|     {% for item in same_barcode_items %} |     {% for other_item in same_barcode_items %} | ||||||
|     <tr> |     <tr> | ||||||
|       <td><a href="/inventory/item/{{ item.item_id }}">{{ item.item_id }}</a></td> |       <td><a href="/inventory/item/{{ other_item.item_id }}">{{ other_item.item_id }}</a></td> | ||||||
|       <td><code>{{ item.item_barcode }}</code></td> |       <td><code>{{ other_item.item_barcode }}</code></td> | ||||||
|       <td>{{ item.name }}</td> |       <td>{{ other_item.name }}</td> | ||||||
|       <td class="--align-right">{{ format_currency(item.unit_price) }}</td> |       <td class="--align-right">{{ format_currency(item.unit_price) }}</td> | ||||||
|       <td>{{ format_date(item.bought) }}</td> |       <td>{{ format_date(item.bought) }}</td> | ||||||
|       <td>{{ item.group_name }} ({{ item.item_group }})</td> |       <td>{{ other_item.group_name }} ({{ other_item.item_group }})</td> | ||||||
|       <td class="--align-right">{{ item.sales_units }}</td> |       <td class="--align-right">{{ other_item.sales_units }}</td> | ||||||
|       <td class="--align-right">{% if item.correction_delta > 0 %}+{% endif %}{{ item.correction_delta }}</td> |       <td class="--align-right">{% if other_item.correction_delta > 0 %}+{% endif %}{{ other_item.correction_delta }}</td> | ||||||
|       <td class="--align-right">{{ item.units_left }}</td> |       <td class="--align-right">{{ other_item.units_left }}</td> | ||||||
|       <td class="--centered"> |       <td class="--centered"> | ||||||
|         {% if item.active_mappings != 0 %} |         {% if other_item.active_mappings != 0 %} | ||||||
|           {{ item.active_mappings_array | join(", ") }} |           {{ other_item.active_mappings_array | join(", ") }} | ||||||
|         {% else %} |         {% else %} | ||||||
|           - |           - | ||||||
|         {% endif %} |         {% endif %} | ||||||
|       </td> |       </td> | ||||||
|       <td class="--centered">{{ format_bool(item.available) }}</td> |       <td class="--centered">{{ format_bool(other_item.available) }}</td> | ||||||
|  |       <td> | ||||||
|  | 	<form method="POST" action="/inventory/transfer"> | ||||||
|  |           <input type="hidden" name="from_item_id" value="{{ item.item_id }}"> | ||||||
|  |           <input type="hidden" name="to_item_id" value="{{ other_item.item_id }}"> | ||||||
|  | 	  <input type="hidden" name="amount" value="{{ item.units_left }}"> | ||||||
|  | 	  <button{% if not other_item.available or other_item.item_id == item.item_id %} disabled{% endif %}>{{ item.units_left }} Artikel umbuchen</button> | ||||||
|  | 	</form> | ||||||
|  |       </td> | ||||||
|     </tr> |     </tr> | ||||||
|     {% endfor %} |     {% endfor %} | ||||||
|   </table> |   </table> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user