Skip to main content

GoodsReceivedNotePage Implementation Plan

Overview

This document outlines the implementation plan for creating a GoodsReceivedNotePage following the existing patterns established by the PurchaseOrderPage in the FlowPOS workspace.

Context

A Goods Received Note (GRN) is a document used in inventory and procurement processes to record the receipt of goods from a supplier. It is typically issued by the receiving department or warehouse team when goods are delivered and physically checked.

Key Purposes of a GRN

  • Confirmation of delivery – It confirms that the goods listed on a purchase order have been received.
  • Verification – It is used to check whether the items received match the purchase order in terms of quantity and quality.
  • Inventory update – It helps update stock levels in the inventory management system.
  • Accounts payable support – It supports invoice verification before payment is made to the supplier.

Typical Fields in a GRN

  • GRN number
  • Date of receipt
  • Supplier name (from linked Purchase Order)
  • Purchase Order number
  • List of items received (including item description, quantity, and unit)
  • Condition of goods
  • Signature of the person receiving the goods
  • Notes on damages or discrepancies (if any)

1. File Structure

apps/frontend-pwa/src/
├── components/forms/
│ ├── goods-received-note/
│ │ ├── GoodsReceivedNoteForm.tsx
│ │ ├── GoodsReceivedNoteSearch.tsx
│ │ ├── GoodsReceivedNoteList.tsx
│ │ ├── GoodsReceivedNoteItemRow.tsx
│ │ └── GoodsReceivedNoteTotals.tsx
│ └── GoodsReceivedNotePage.tsx
├── services/
│ └── goodsReceivedNoteService.ts
└── types/
└── goodsReceivedNote.ts

2. Type Definitions (types/goodsReceivedNote.ts)

Based on the backend DTO and the curl example, we need to define:

// Core interfaces
interface GoodsReceivedItem {
id?: string;
productId: string;
product?: Product;
quantity: number;
unitPrice: number;
total: number;
notes?: string;
batchNumber?: string;
serialNumber?: string;
inventoryDetails?: InventoryDetail[];
taxes?: TaxDetail[];
}

interface GoodsReceivedNote {
id?: string;
businessId: string;
status: GoodsReceivedNoteStatus;
purchaseOrderId: string;
receivedDate: string;
locationId: string;
locationName: string;
totalAmount: number;
exchangeRate: number;
totalBaseAmount: number;
currencyId: string;
goodsReceivedDetail: {
items: GoodsReceivedItem[];
};
paymentDetail: Record<string, any>;
note?: string;
createdBy?: string;
createdAt?: string;
updatedAt?: string;
}

interface GoodsReceivedNoteFormData {
id?: string;
purchaseOrderId: string;
receivedDate: Date;
status: GoodsReceivedNoteStatus;
items: GoodsReceivedItem[];
note?: string;
currencyId: string;
}

3. Service Layer (services/goodsReceivedNoteService.ts)

Following the same pattern as purchaseOrderService.ts:

// Core CRUD operations
- getGoodsReceivedNotes()
- getGoodsReceivedNoteById()
- createGoodsReceivedNote()
- updateGoodsReceivedNote()
- deleteGoodsReceivedNote()
- searchGoodsReceivedNotes()
- getGoodsReceivedNotesByPurchaseOrder()

// PDF operations (if needed)
- generateGoodsReceivedNotePDF()
- downloadGoodsReceivedNotePDF()
- getGoodsReceivedNotePrintPreview()

4. Main Page Component (GoodsReceivedNotePage.tsx)

Following the same pattern as PurchaseOrderPage.tsx:

Key Features

  • Tab-based interface (Search existing GRNs / Create new GRN)
  • Form submission handling with error management
  • Loading states and user feedback
  • Integration with authentication and business context
  • Success/error toast notifications

State Management

  • isSubmitting - form submission state
  • error - error handling
  • createdGoodsReceivedNote - newly created GRN
  • Form reference for reset functionality

5. Form Component (GoodsReceivedNoteForm.tsx)

Following the same pattern as PurchaseOrderForm.tsx:

Key Features

  • Purchase Order selector (to link GRN to existing PO)
  • Date picker for received date
  • Status selector (DRAFT, SUBMITTED, REVIEWED)
  • Items list with product selection, quantities, and pricing
  • Currency selection
  • Notes field
  • Form validation using Zod schema
  • Item management (add/remove items)

Form Schema

const goodsReceivedNoteSchema = z.object({
id: z.string().optional(),
purchaseOrderId: z.string().min(1, "Purchase Order is required"),
receivedDate: z.date({ required_error: "Received date is required" }),
status: z.nativeEnum(GoodsReceivedNoteStatus),
items: z.array(z.object({
productId: z.string().min(1, "Product is required"),
quantity: z.number().min(1, "Quantity must be at least 1"),
unitPrice: z.number().min(0, "Unit price must be positive"),
notes: z.string().optional(),
batchNumber: z.string().optional(),
serialNumber: z.string().optional(),
})).min(1, "At least one item is required"),
note: z.string().optional(),
currencyId: z.string().min(1, "Currency is required"),
});

6. Search Component (GoodsReceivedNoteSearch.tsx)

Following the same pattern as PurchaseOrderSearch.tsx:

Key Features

  • Search by GRN number, supplier, or purchase order
  • Date range filtering
  • Status filtering
  • Pagination
  • Results display with key information
  • Selection functionality

7. List and Item Components

  • GoodsReceivedNoteList.tsx - Container for items
  • GoodsReceivedNoteItemRow.tsx - Individual item row with product selector, quantities, pricing
  • GoodsReceivedNoteTotals.tsx - Summary calculations

8. Key Differences from PurchaseOrderPage

GRN-Specific Features

  1. Purchase Order Linking: GRNs are always linked to an existing Purchase Order
  2. Received Date: Focus on when goods were actually received vs. expected delivery
  3. Status Flow: DRAFT → SUBMITTED → REVIEWED (different from PO statuses)
  4. Inventory Integration: GRNs directly affect inventory levels when submitted
  5. Batch/Serial Numbers: Support for tracking individual items
  6. Tax Handling: Support for tax calculations per item
  7. Inventory Details: Support for multiple batch/serial numbers per item

Form Differences

  • No supplier selection (comes from linked PO)
  • No delivery date (uses received date instead)
  • No payment terms (handled by PO)
  • No shipping/billing addresses (from PO)
  • Added batch/serial number fields
  • Added inventory details support

9. Integration Points

Required Components

  • PurchaseOrderSelector - to select linked PO
  • ProductSelector - for item selection
  • CurrencySelector - for currency selection
  • LocationSelector - for receiving location
  • InventoryDetailBatch - for batch number management
  • InventoryDetailSerial - for serial number management

Context Dependencies

  • useAuth() - for authentication
  • useCurrentBusiness() - for business context
  • useCurrentLocation() - for location context
  • useBusinessCurrencies() - for currency options
  • useFetchUser() - for user information

10. API Integration

Backend Endpoints to Use

  • POST /goods-received-notes - Create GRN
  • GET /goods-received-notes - List GRNs with pagination
  • GET /goods-received-notes/:id - Get specific GRN
  • PATCH /goods-received-notes/:id - Update GRN
  • DELETE /goods-received-notes/:id - Delete GRN
  • GET /goods-received-notes/purchase-order/:purchaseOrderId - Get GRNs by PO
  • PUT /goods-received-notes/:id/submit - Submit GRN

Example API Request (from curl)

{
"businessId": "e67fc0f8-446b-4608-ad44-c83126a84b87",
"createdBy": "f04b2250-34a0-409c-bb57-612d863851c9",
"status": "submitted",
"purchaseOrderId": "88d61ded-19b4-4176-afed-8d57d2923115",
"receivedDate": "2025-07-05T02:38:07.165Z",
"locationId": "8ae12985-6ff3-44e7-a4cf-71602a042ae2",
"locationName": "ANTIGUA",
"totalAmount": 95.00,
"exchangeRate": 7.90,
"totalBaseAmount": 84.821427,
"currencyId": "92a7a47e-7ef5-4b16-8b74-0a18bdbaf7b2",
"goodsReceivedDetail": {
"items": [
{
"id": "72175622-a8cb-474f-98b2-1be4857dffe1",
"businessId": "e67fc0f8-446b-4608-ad44-c83126a84b87",
"status": "ACTIVE",
"createdAt": "2025-07-05T02:38:07.165Z",
"createdBy": "f04b2250-34a0-409c-bb57-612d863851c9",
"locationId": "8ae12985-6ff3-44e7-a4cf-71602a042ae2",
"locationName": "ANTIGUA",
"productId": "3e44dcfa-f349-4e9e-be38-828b8377c058",
"productName": "Generic Cotton Chips",
"goodOrService": "B",
"quantity": 9.00,
"unitPrice": 5.00,
"total": 45.00,
"taxes": [
{
"shortName": "IVA",
"taxableUnitCode": "1",
"taxableAmount": 40.178571,
"taxAmount": 4.821429
}
],
"inventoryDetails": [
{
"batchNumber": "89967",
"quantity": 3
},
{
"batchNumber": "89973",
"quantity": 6
}
],
"product": {
"id": "3e44dcfa-f349-4e9e-be38-828b8377c058",
"name": "Generic Cotton Chips"
}
}
]
},
"paymentDetail": {}
}

11. Translation Keys Needed

// Add to i18n files
goodsReceivedNote: {
title: "Goods Received Note",
newDocument: "New GRN",
searchExisting: "Search Existing GRNs",
document: "GRN Document",
selectPurchaseOrder: "Select Purchase Order",
receivedDate: "Received Date",
status: "Status",
items: "Received Items",
addItem: "Add Item",
notes: "Notes",
save: "Save GRN",
update: "Update GRN",
successCreate: "GRN created successfully",
successUpdate: "GRN updated successfully",
error: "Failed to save GRN",
invalidItems: "Please check all items are valid",
statuses: {
draft: "Draft",
submitted: "Submitted",
reviewed: "Reviewed"
}
}

12. Implementation Steps

  1. Create Type Definitions - Define all interfaces and types
  2. Create Service Layer - Implement API service functions
  3. Create Form Components - Build the form structure and validation
  4. Create Search Components - Implement search and listing functionality
  5. Create Main Page - Integrate all components and handle state
  6. Add Translations - Add all required translation keys
  7. Testing - Test all CRUD operations and edge cases
  8. Integration Testing - Test with existing Purchase Order functionality

13. Considerations

Performance

  • Implement proper loading states
  • Use pagination for large datasets
  • Optimize re-renders with proper memoization

User Experience

  • Clear error messages and validation feedback
  • Intuitive form flow
  • Responsive design for mobile devices
  • Keyboard navigation support

Data Integrity

  • Validate all required fields
  • Ensure proper data types
  • Handle API errors gracefully
  • Maintain data consistency with linked Purchase Orders

Security

  • Validate user permissions
  • Sanitize all inputs
  • Handle sensitive data appropriately
  • Implement proper authentication checks

This plan provides a comprehensive foundation for creating a GoodsReceivedNotePage that follows the existing patterns in the codebase while addressing the specific requirements of GRN functionality.