# Stock Tool GUI v2 - Fixes Applied ## Summary Fixed three critical issues in `stock_tool_gui_v2.py`: 1. ✅ Encoding issue with barcode part numbers 2. ✅ API response handling causing "'list' object has no attribute 'get'" errors 3. ✅ Duplicate stock items being created when adding to existing location --- ## Issue 1: Encoding Problem with Part Numbers ### Problem Raw scan data contained: `pm:STHW4-DU-HS24041¡­` The non-ASCII characters (¡­) were being included in the parsed part number. ### Root Cause The `parse_scan()` function was not cleaning/sanitizing the extracted part codes. ### Fix Applied Added `clean_part_code()` helper function that: - Filters out all non-ASCII characters - Keeps only printable ASCII characters (codes 32-126) - Removes encoding artifacts like `¡­` ### Location File: `stock_tool_gui_v2.py` Function: `parse_scan()` (lines 294-348) ### Result - **Before**: `STHW4-DU-HS24041¡­` - **After**: `STHW4-DU-HS24041` ✓ --- ## Issue 2: API Response Handling Error ### Problem Error: `'list' object has no attribute 'get'` - Stock not being added to InvenTree - Stock levels not updating after adding items ### Root Cause The InvenTree API POST response can return either: - A dictionary: `{'pk': 123, 'quantity': 150, ...}` - A list: `[{'pk': 123, 'quantity': 150, ...}]` The code was assuming it would always be a dict and calling `.get()` directly on the response, which failed when the API returned a list. ### Locations with the Bug 1. `_add_stock()` function - line 806 (original) 2. `_update_stock()` function - line 865 (original) 3. Misplaced `get_stock_level()` function at top of file ### Fixes Applied #### 1. Fixed `_add_stock()` function (lines 797-827) **Before:** ```python r.raise_for_status() sid = r.json().get('pk', r.json().get('id')) # ❌ Fails if response is list ``` **After:** ```python r.raise_for_status() # Handle response - might be list or dict response_data = r.json() if isinstance(response_data, list): stock_item = response_data[0] if response_data else {} else: stock_item = response_data sid = stock_item.get('pk', stock_item.get('id')) # ✓ Works for both ``` #### 2. Fixed `_update_stock()` function (lines 858-875) Applied the same fix for consistency. #### 3. Moved `get_stock_level()` function (lines 256-270) - Removed misplaced definition from top of file (before imports) - Re-added in correct location after `find_stock_item()` function --- ## Issue 3: Duplicate Stock Items Created ### Problem When scanning a part that already exists at a storage location, the tool was creating a duplicate stock item instead of adding to the existing quantity. **Example:** - Location C64_PSU has 150x STHW4-DU-HS24041 - Scan barcode to add 100 more - **Bug**: Creates second stock item with 100 (now have two separate items) - **Expected**: Updates existing item to 250 ### Root Cause The `_add_stock()` function was always creating a new stock item via POST without checking if one already existed at that location. ### Fix Applied (lines 791-845) **Before:** ```python def _add_stock(self, part_id: int, part_code: str, quantity: Optional[int]): # Always creates new stock item - WRONG! r = requests.post(f"{self.host}/api/stock/", ...) ``` **After:** ```python def _add_stock(self, part_id: int, part_code: str, quantity: Optional[int]): # Check if stock item already exists at this location existing = find_stock_item(self.host, self.token, part_id, self.current_loc) if existing: # Stock exists - update the quantity by adding to it sid = existing.get('pk', existing.get('id')) new_stock = current_stock + quantity r = requests.patch(f"{self.host}/api/stock/{sid}/", json={'quantity': new_stock}) # Updates existing item ✓ else: # No existing stock - create new stock item r = requests.post(f"{self.host}/api/stock/", ...) # Creates new item ✓ ``` ### Behavior Now - **Same part + same location** = Updates existing stock item (no duplicate) - **Same part + different location** = Creates new stock item (correct) - **New part** = Creates new stock item (correct) --- ## Testing ### Test Files Created 1. `test_parse_fix.py` - Verifies encoding fix 2. `test_stock_level.py` - Verifies stock level retrieval 3. `test_add_stock.py` - Verifies API response handling 4. `test_duplicate_handling.py` - Verifies duplicate prevention logic ### Test Results All tests pass ✓ --- ## Expected Behavior Now ### When scanning barcode: ``` {pbn:PICK251017100019,on:WM2510170196,pc:C18548292,pm:STHW4-DU-HS24041¡­,qty:150,mc:,cc:1,pdi:180368458,hp:null,wc:JS} ``` The tool will: 1. ✅ Extract clean part number: `STHW4-DU-HS24041` 2. ✅ Extract quantity: `150` 3. ✅ Check if part already exists at current location 4. ✅ If exists: Add to existing stock (no duplicate created) 5. ✅ If new: Create new stock item 6. ✅ Display updated stock levels 7. ✅ Handle both dict and list API responses correctly ### Example Workflows **Scenario 1: First time adding part to location** - Scan: Part STHW4-DU-HS24041, Qty: 150 - Result: Creates new stock item - Log: `✔ Created new stock item for 'STHW4-DU-HS24041' → StockItem #123` - Log: `📊 Stock: 0 → 150 (+150)` **Scenario 2: Adding more of same part to same location** - Scan: Part STHW4-DU-HS24041, Qty: 100 - Result: Updates existing stock item #123 - Log: `✔ Added 100× to existing 'STHW4-DU-HS24041' (StockItem #123)` - Log: `📊 Stock: 150 → 250 (+100)` - **No duplicate created!** ✓ **Scenario 3: Adding same part to different location** - Change location to C65_PSU - Scan: Part STHW4-DU-HS24041, Qty: 75 - Result: Creates new stock item #124 at the new location - Log: `✔ Created new stock item for 'STHW4-DU-HS24041' → StockItem #124` - Log: `📊 Stock: 0 → 75 (+75)` --- ## Files Modified - `stock_tool_gui_v2.py` - Main application file ## Files Created - `test_parse_fix.py` - Test for encoding fix - `test_stock_level.py` - Test for stock level retrieval - `test_add_stock.py` - Test for API response handling - `FIXES_APPLIED.md` - This document