Fix Purchase Order modal and reorganize documentation

Frontend Changes:
- Fix runtime error: Remove undefined handleModify reference from ActionQueueCard in DashboardPage
- Migrate PurchaseOrderDetailsModal to use correct PurchaseOrderItem type from purchase_orders service
- Fix item display: Parse unit_price as string (Decimal) instead of number
- Use correct field names: item_notes instead of notes
- Remove deprecated PurchaseOrder types from suppliers.ts to prevent type conflicts
- Update CreatePurchaseOrderModal to use unified types
- Clean up API exports: Remove old PO hooks re-exported from suppliers
- Add comprehensive translations for PO modal (en, es, eu)

Documentation Reorganization:
- Move WhatsApp implementation docs to docs/03-features/notifications/whatsapp/
- Move forecast validation docs to docs/03-features/forecasting/
- Move specification docs to docs/03-features/specifications/
- Move deployment docs (Colima, K8s, VPS sizing) to docs/05-deployment/
- Archive completed implementation summaries to docs/archive/implementation-summaries/
- Delete obsolete FRONTEND_CHANGES_NEEDED.md
- Standardize filenames to lowercase with hyphens

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Urtzi Alfaro
2025-11-18 11:59:23 +01:00
parent 5c45164c8e
commit 3c3d3ce042
32 changed files with 654 additions and 874 deletions

View File

@@ -49,6 +49,8 @@ export interface ReasoningInputs {
aiInsights: boolean;
}
// Note: This is a different interface from PurchaseOrderSummary in purchase_orders.ts
// This is specifically for OrchestrationSummary dashboard display
export interface PurchaseOrderSummary {
supplierName: string;
itemCategories: string[];

View File

@@ -10,6 +10,7 @@ import type {
PurchaseOrderDetail,
PurchaseOrderSearchParams,
PurchaseOrderUpdateData,
PurchaseOrderCreateData,
PurchaseOrderStatus,
CreateDeliveryInput,
DeliveryResponse
@@ -19,6 +20,7 @@ import {
getPurchaseOrder,
getPendingApprovalPurchaseOrders,
getPurchaseOrdersByStatus,
createPurchaseOrder,
updatePurchaseOrder,
approvePurchaseOrder,
rejectPurchaseOrder,
@@ -112,6 +114,37 @@ export const usePurchaseOrder = (
});
};
/**
* Hook to create a new purchase order
*/
export const useCreatePurchaseOrder = (
options?: UseMutationOptions<
PurchaseOrderDetail,
ApiError,
{ tenantId: string; data: PurchaseOrderCreateData }
>
) => {
const queryClient = useQueryClient();
return useMutation<
PurchaseOrderDetail,
ApiError,
{ tenantId: string; data: PurchaseOrderCreateData }
>({
mutationFn: ({ tenantId, data }) => createPurchaseOrder(tenantId, data),
onSuccess: (data, variables) => {
// Invalidate all lists to refresh with new PO
queryClient.invalidateQueries({ queryKey: purchaseOrderKeys.lists() });
// Add to cache
queryClient.setQueryData(
purchaseOrderKeys.detail(variables.tenantId, data.id),
data
);
},
...options,
});
};
/**
* Hook to update a purchase order
*/

View File

@@ -15,11 +15,6 @@ import type {
SupplierSearchParams,
SupplierStatistics,
SupplierDeletionSummary,
PurchaseOrderCreate,
PurchaseOrderUpdate,
PurchaseOrderResponse,
PurchaseOrderApproval,
PurchaseOrderSearchParams,
DeliveryCreate,
DeliveryUpdate,
DeliveryResponse,
@@ -49,15 +44,6 @@ export const suppliersKeys = {
byType: (tenantId: string, supplierType: string) =>
[...suppliersKeys.suppliers.all(), 'by-type', tenantId, supplierType] as const,
},
purchaseOrders: {
all: () => [...suppliersKeys.all, 'purchase-orders'] as const,
lists: () => [...suppliersKeys.purchaseOrders.all(), 'list'] as const,
list: (params?: PurchaseOrderSearchParams) =>
[...suppliersKeys.purchaseOrders.lists(), params] as const,
details: () => [...suppliersKeys.purchaseOrders.all(), 'detail'] as const,
detail: (orderId: string) =>
[...suppliersKeys.purchaseOrders.details(), orderId] as const,
},
deliveries: {
all: () => [...suppliersKeys.all, 'deliveries'] as const,
lists: () => [...suppliersKeys.deliveries.all(), 'list'] as const,
@@ -173,35 +159,6 @@ export const useSuppliersByType = (
});
};
// Purchase Order Queries
export const usePurchaseOrders = (
tenantId: string,
queryParams?: PurchaseOrderSearchParams,
options?: Omit<UseQueryOptions<PurchaseOrderResponse[], ApiError>, 'queryKey' | 'queryFn'>
) => {
return useQuery<PurchaseOrderResponse[], ApiError>({
queryKey: suppliersKeys.purchaseOrders.list(queryParams),
queryFn: () => suppliersService.getPurchaseOrders(tenantId, queryParams as any),
enabled: !!tenantId,
staleTime: 1 * 60 * 1000, // 1 minute
...options,
});
};
export const usePurchaseOrder = (
tenantId: string,
orderId: string,
options?: Omit<UseQueryOptions<PurchaseOrderResponse, ApiError>, 'queryKey' | 'queryFn'>
) => {
return useQuery<PurchaseOrderResponse, ApiError>({
queryKey: suppliersKeys.purchaseOrders.detail(orderId),
queryFn: () => suppliersService.getPurchaseOrder(tenantId, orderId),
enabled: !!tenantId && !!orderId,
staleTime: 2 * 60 * 1000, // 2 minutes
...options,
});
};
// Delivery Queries
export const useDeliveries = (
tenantId: string,
@@ -462,94 +419,6 @@ export const useHardDeleteSupplier = (
});
};
// Purchase Order Mutations
export const useCreatePurchaseOrder = (
options?: UseMutationOptions<PurchaseOrderResponse, ApiError, PurchaseOrderCreate>
) => {
const queryClient = useQueryClient();
return useMutation<PurchaseOrderResponse, ApiError, PurchaseOrderCreate>({
mutationFn: (orderData) => suppliersService.createPurchaseOrder(orderData),
onSuccess: (data) => {
// Add to cache
queryClient.setQueryData(
suppliersKeys.purchaseOrders.detail(data.id),
data
);
// Invalidate lists
queryClient.invalidateQueries({
queryKey: suppliersKeys.purchaseOrders.lists()
});
},
...options,
});
};
export const useUpdatePurchaseOrder = (
options?: UseMutationOptions<
PurchaseOrderResponse,
ApiError,
{ orderId: string; updateData: PurchaseOrderUpdate }
>
) => {
const queryClient = useQueryClient();
return useMutation<
PurchaseOrderResponse,
ApiError,
{ orderId: string; updateData: PurchaseOrderUpdate }
>({
mutationFn: ({ orderId, updateData }) =>
suppliersService.updatePurchaseOrder(orderId, updateData),
onSuccess: (data, { orderId }) => {
// Update cache
queryClient.setQueryData(
suppliersKeys.purchaseOrders.detail(orderId),
data
);
// Invalidate lists
queryClient.invalidateQueries({
queryKey: suppliersKeys.purchaseOrders.lists()
});
},
...options,
});
};
export const useApprovePurchaseOrder = (
options?: UseMutationOptions<
PurchaseOrderResponse,
ApiError,
{ orderId: string; approval: PurchaseOrderApproval }
>
) => {
const queryClient = useQueryClient();
return useMutation<
PurchaseOrderResponse,
ApiError,
{ orderId: string; approval: PurchaseOrderApproval }
>({
mutationFn: ({ orderId, approval }) =>
suppliersService.approvePurchaseOrder(orderId, approval),
onSuccess: (data, { orderId }) => {
// Update cache
queryClient.setQueryData(
suppliersKeys.purchaseOrders.detail(orderId),
data
);
// Invalidate lists
queryClient.invalidateQueries({
queryKey: suppliersKeys.purchaseOrders.lists()
});
},
...options,
});
};
// Delivery Mutations
export const useCreateDelivery = (
options?: UseMutationOptions<DeliveryResponse, ApiError, DeliveryCreate>