feat: enhance Letzshop order import with EAN matching and stats

- Add historical order import with pagination support
- Add customer_locale, shipping_country_iso, billing_country_iso columns
- Add gtin/gtin_type columns to Product table for EAN matching
- Fix order stats to count all orders server-side (not just visible page)
- Add GraphQL introspection script with tracking workaround tests
- Enrich inventory units with EAN, MPN, SKU, product name
- Add LetzshopOrderStats schema for proper status counts

Migrations:
- a9a86cef6cca: Add locale and country fields to letzshop_orders
- cb88bc9b5f86: Add gtin columns to products table

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-18 21:04:33 +01:00
parent 6d6c8b44d3
commit 0ab10128ae
17 changed files with 3451 additions and 94 deletions

View File

@@ -1,21 +1,57 @@
{# app/templates/admin/partials/letzshop-orders-tab.html #}
{# Orders tab for admin Letzshop management #}
<!-- Header with Import Button -->
<!-- Header with Import Buttons -->
<div class="flex items-center justify-between mb-6">
<div>
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200">Orders</h3>
<p class="text-sm text-gray-500 dark:text-gray-400">Manage Letzshop orders for this vendor</p>
</div>
<button
@click="importOrders()"
:disabled="!letzshopStatus.is_configured || importingOrders"
class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple disabled:opacity-50 disabled:cursor-not-allowed"
>
<span x-show="!importingOrders" x-html="$icon('download', 'w-4 h-4 mr-2')"></span>
<span x-show="importingOrders" x-html="$icon('spinner', 'w-4 h-4 mr-2')"></span>
<span x-text="importingOrders ? 'Importing...' : 'Import Orders'"></span>
</button>
<div class="flex gap-2">
<button
@click="importHistoricalOrders()"
:disabled="!letzshopStatus.is_configured || importingHistorical"
class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-gray-700 dark:text-gray-300 transition-colors duration-150 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed"
title="Import all historical confirmed orders"
>
<span x-show="!importingHistorical" x-html="$icon('archive', 'w-4 h-4 mr-2')"></span>
<span x-show="importingHistorical" x-html="$icon('spinner', 'w-4 h-4 mr-2')"></span>
<span x-text="importingHistorical ? 'Importing...' : 'Import History'"></span>
</button>
<button
@click="importOrders()"
:disabled="!letzshopStatus.is_configured || importingOrders"
class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple disabled:opacity-50 disabled:cursor-not-allowed"
>
<span x-show="!importingOrders" x-html="$icon('download', 'w-4 h-4 mr-2')"></span>
<span x-show="importingOrders" x-html="$icon('spinner', 'w-4 h-4 mr-2')"></span>
<span x-text="importingOrders ? 'Importing...' : 'Import New'"></span>
</button>
</div>
</div>
<!-- Historical Import Result -->
<div x-show="historicalImportResult" x-transition class="mb-6 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
<div class="flex items-start justify-between">
<div class="flex items-start">
<span x-html="$icon('check-circle', 'w-5 h-5 text-blue-500 mr-3 mt-0.5')"></span>
<div>
<h4 class="font-medium text-blue-800 dark:text-blue-200">Historical Import Complete</h4>
<div class="text-sm text-blue-700 dark:text-blue-300 mt-1">
<span x-text="historicalImportResult?.imported + ' imported'"></span> ·
<span x-text="historicalImportResult?.updated + ' updated'"></span> ·
<span x-text="historicalImportResult?.skipped + ' skipped'"></span>
</div>
<div x-show="historicalImportResult?.products_matched > 0 || historicalImportResult?.products_not_found > 0" class="text-sm text-blue-600 dark:text-blue-400 mt-1">
<span x-text="historicalImportResult?.products_matched + ' products matched by EAN'"></span> ·
<span x-text="historicalImportResult?.products_not_found + ' not found'"></span>
</div>
</div>
</div>
<button @click="historicalImportResult = null" class="text-blue-500 hover:text-blue-700">
<span x-html="$icon('x', 'w-4 h-4')"></span>
</button>
</div>
</div>
<!-- Status Cards -->