Skip to content

Physical Inventory Count Guide

Overview

Physical Inventory Counts reconcile actual on-hand stock with system records by counting physical inventory and adjusting for discrepancies. This process is essential for maintaining inventory accuracy, identifying shrinkage, detecting errors, and ensuring financial reporting integrity.

The system automatically calculates variances, creates adjustment movements, and maintains an immutable audit trail for regulatory compliance.

Table of Contents

Core Concepts

What is a Physical Count?

A physical count compares actual counted quantity with system quantity and adjusts inventory to match reality:

System Record (Before Count):
Product: Laptop - Dell XPS 13
Warehouse: Main DC
Quantity on Hand: 100 units
Reserved: 10 units
Available: 90 units

Physical Count:
Counted Quantity: 98 units

System Record (After Count):
Quantity on Hand: 98 units
Reserved: 10 units
Available: 88 units
Variance: -2 units (shrinkage)

Why Perform Physical Counts?

Regulatory Compliance:

  • Required by GAAP, IFRS for financial reporting
  • SOX compliance for inventory valuation
  • Tax audit requirements

Operational Accuracy:

  • Detect theft, damage, or loss (shrinkage)
  • Identify data entry errors
  • Prevent stockouts from inaccurate records
  • Improve order fulfillment accuracy

Financial Integrity:

  • Accurate cost of goods sold (COGS)
  • Correct inventory asset valuation
  • Reliable financial statements

Process Improvement:

  • Identify systemic issues
  • Improve warehouse procedures
  • Reduce inventory variance over time

Physical Count Model

The system records:

json
{
  "product_id": 42,
  "warehouse_id": 1,
  "counted_quantity": 98,
  "system_quantity_before": 100,
  "variance": -2,
  "variance_percentage": -2.0,
  "counted_by": 5,
  "counted_at": "2025-01-16T10:00:00.000000Z",
  "adjustment_movement_id": 892
}

Key Fields:

  • counted_quantity: Actual counted units
  • system_quantity_before: System quantity before adjustment
  • variance: Difference (counted - system)
  • variance_percentage: Variance as percentage of system quantity
  • adjustment_movement_id: Stock movement created to correct variance

Count Types

Full Physical Count (Annual):

  • Count all products in all warehouses
  • Usually performed at year-end
  • Most time-consuming but most accurate

Cycle Count (Ongoing):

  • Count subset of products on rotating schedule
  • Example: 20% of products weekly
  • Spreads workload throughout year
  • Maintains continuous accuracy

Spot Count (Ad-hoc):

  • Count specific products as needed
  • Triggered by suspected discrepancy
  • Quick response to issues

ABC Count (Priority-based):

  • A items (high value): Count monthly
  • B items (medium value): Count quarterly
  • C items (low value): Count annually
  • Focuses effort on high-impact products

When to Perform Counts

Annual Full Count:

  • End of fiscal year
  • Before financial statement preparation
  • All products, all warehouses
  • Complete reconciliation

Quarterly Cycle Counts:

  • 25% of products each quarter
  • Focus on high-value items
  • Maintain ongoing accuracy
  • Detect issues early

Monthly Spot Counts:

  • Products with recent discrepancies
  • High-theft items
  • Fast-moving products
  • Critical stock items

Event-Triggered Counts:

  • After major shipment received
  • Before warehouse reorganization
  • When variance suspected
  • After inventory system migration

ABC Analysis Schedule

Categorize products by annual dollar volume:

A Items (70-80% of value, 10-20% of SKUs):

  • Count: Monthly
  • Examples: High-value electronics, jewelry
  • Priority: Critical

B Items (15-25% of value, 30-40% of SKUs):

  • Count: Quarterly
  • Examples: Mid-range products
  • Priority: Important

C Items (5-10% of value, 40-50% of SKUs):

  • Count: Annually
  • Examples: Low-cost consumables
  • Priority: Standard

Count Procedures

Step-by-Step Process

1. Preparation Phase

Plan the Count:

  • Schedule during low-activity period
  • Assign count teams
  • Prepare count sheets or mobile devices
  • Freeze transactions (optional)

Organize Warehouse:

  • Clean and organize storage areas
  • Group similar products
  • Label bin locations clearly
  • Separate damaged/quarantined items

2. Counting Phase

Count Instructions:

  • Count each product in designated area
  • Don't reference system quantities (blind count)
  • Use two-person teams for accuracy
  • Record bin locations
  • Note damaged or obsolete items

Count Sheet Example:

Product: Laptop - Dell XPS 13
SKU: DELL-XPS13-001
Warehouse: Main DC
Location: A-12-3

Counter 1: 98 units
Counter 2: 98 units
Match: ✅ Yes

Notes: All units in good condition

3. Recording Phase

Enter Counts into System:

  • Record counted quantities via API
  • System calculates variances automatically
  • Review large variances before accepting
  • Create adjustment movements

4. Investigation Phase

Investigate Variances:

  • Recount if variance > threshold (e.g., 5% or $500 value)
  • Check recent transactions
  • Review movement history
  • Interview staff if significant discrepancy

5. Adjustment Phase

Accept Count:

  • System adjusts inventory to match count
  • Creates stock movement record
  • Updates last_counted_at timestamp
  • Generates variance report

Document Findings:

  • Record reasons for variances
  • Note process improvements needed
  • Update procedures if systemic issues found

Recording Physical Counts

Record Physical Count

Submit counted quantity to reconcile inventory:

Endpoint: POST /api/v1/operations/inventory/physical-count

Request:

bash
curl -X POST "https://api.crm.test/api/v1/operations/inventory/physical-count" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": 42,
    "warehouse_id": 1,
    "counted_quantity": 98
  }'

Request Parameters:

ParameterTypeRequiredDescription
product_idinteger✅ YesProduct being counted
warehouse_idintegerNoWarehouse location (null = default)
counted_quantityinteger✅ YesActual counted units (≥ 0)

Response (200 OK):

json
{
  "message": "Physical count recorded successfully",
  "data": {
    "id": 123,
    "product_id": 42,
    "warehouse_id": 1,
    "quantity_on_hand": 98,
    "quantity_reserved": 10,
    "quantity_available": 88,
    "reorder_point": 20,
    "reorder_quantity": 50,
    "last_counted_at": "2025-01-16T10:00:00.000000Z",
    "last_movement_at": "2025-01-16T10:00:00.000000Z",
    "warehouse": {
      "id": 1,
      "name": "Main Distribution Center",
      "code": "MDC",
      "type": "distribution"
    },
    "product": {
      "id": 42,
      "name": "Laptop - Dell XPS 13",
      "sku": "DELL-XPS13-001",
      "type": "standard"
    },
    "created_at": "2024-12-01T00:00:00.000000Z",
    "updated_at": "2025-01-16T10:00:00.000000Z"
  }
}

What Happens:

  1. System retrieves current inventory:

    • Current quantity_on_hand: 100 units
  2. Calculates variance:

    • Variance: 98 (counted) - 100 (system) = -2 units
  3. Creates adjustment movement (if variance ≠ 0):

    • Movement type: physical_count
    • Quantity: -2
    • Reason: "physical_count"
  4. Updates inventory:

    • quantity_on_hand: 100 → 98
    • last_counted_at: Updated to current timestamp
  5. Dispatches domain event:

    • InventoryCountCompleted event fired
    • Contains variance details for reporting

No Variance Example

If counted quantity matches system:

Request:

json
{
  "product_id": 42,
  "warehouse_id": 1,
  "counted_quantity": 100
}

System Behavior:

  • Variance: 0 units
  • No adjustment movement created (no change needed)
  • last_counted_at: Updated to current timestamp
  • inventory record: Not modified (already correct)

Response:

json
{
  "message": "Physical count recorded successfully",
  "data": {
    "quantity_on_hand": 100,
    "last_counted_at": "2025-01-16T10:00:00.000000Z"
  }
}

Multiple Products Count

Record counts for multiple products:

bash
# Product 1
curl -X POST "https://api.crm.test/api/v1/operations/inventory/physical-count" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": 42,
    "warehouse_id": 1,
    "counted_quantity": 98
  }'

# Product 2
curl -X POST "https://api.crm.test/api/v1/operations/inventory/physical-count" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": 43,
    "warehouse_id": 1,
    "counted_quantity": 145
  }'

# Product 3
curl -X POST "https://api.crm.test/api/v1/operations/inventory/physical-count" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": 44,
    "warehouse_id": 1,
    "counted_quantity": 0
  }'

Variance Handling

Understanding Variances

Variance Formula:

Variance = Counted Quantity - System Quantity
Variance % = (Variance / System Quantity) × 100

Examples:

Negative Variance (Shrinkage):

System: 100 units
Counted: 98 units
Variance: -2 units (-2%)
Reason: Theft, damage, data entry error

Positive Variance (Overage):

System: 100 units
Counted: 103 units
Variance: +3 units (+3%)
Reason: Data entry error, unreported receipt

No Variance (Accurate):

System: 100 units
Counted: 100 units
Variance: 0 units (0%)
Reason: System is accurate

Variance Thresholds

Implement variance investigation rules:

Recount Threshold:

  • Variance > 5% or $500 value
  • Requires second count before accepting

Approval Threshold:

  • Variance > 10% or $2,000 value
  • Requires manager approval

Investigation Threshold:

  • Variance > 20% or $5,000 value
  • Requires formal investigation

Example:

Product: Laptop - Dell XPS 13
Cost: $1,200 per unit

Variance: -5 units
Value: $6,000 loss
Action: ✅ Trigger investigation (> $5,000)

Variance: -2 units
Value: $2,400 loss
Action: ✅ Require approval (> $2,000)

Variance: -1 unit
Value: $1,200 loss
Action: ✅ Recount (> $500)

Common Variance Causes

Negative Variances (Shrinkage):

  • Theft: Internal or external
  • Damage: Unreported damage/disposal
  • Data Entry: Incorrect receipts recorded
  • Location: Product in wrong location (not counted)
  • Shipping: Shipped but not recorded

Positive Variances (Overage):

  • Data Entry: Incorrect shipment recording
  • Returns: Unreported returns
  • Location: Product counted in multiple locations
  • Receipts: Received but not recorded

Viewing Variance Reports

Get product movement history:

bash
curl -X GET "https://api.crm.test/api/v1/operations/stock-movements/product/42/history" \
  -H "Authorization: Bearer {token}"

Filter for physical count movements:

bash
curl -X GET "https://api.crm.test/api/v1/operations/stock-movements?movement_type=physical_count" \
  -H "Authorization: Bearer {token}"

Get movement details:

bash
curl -X GET "https://api.crm.test/api/v1/operations/stock-movements/892" \
  -H "Authorization: Bearer {token}"

Response (Physical Count Movement):

json
{
  "data": {
    "id": 892,
    "product_id": 42,
    "warehouse_id": 1,
    "movement_type": {
      "value": "physical_count",
      "label": "Physical Count"
    },
    "is_inbound": false,
    "is_outbound": true,
    "quantity": -2,
    "quantity_before": 100,
    "quantity_after": 98,
    "product": {
      "id": 42,
      "name": "Laptop - Dell XPS 13",
      "sku": "DELL-XPS13-001"
    },
    "warehouse": {
      "id": 1,
      "name": "Main Distribution Center",
      "code": "MDC"
    },
    "reason": "physical_count",
    "notes": null,
    "created_by": 5,
    "creator": {
      "id": 5,
      "name": "Inventory Manager",
      "email": "inventory@example.com"
    },
    "created_at": "2025-01-16T10:00:00.000000Z"
  }
}

Count Validation

Validation Rules

1. Product Validation

json
{
  "product_id": 99999
}
// ❌ Error: Selected product does not exist

Product must exist in the system.

2. Warehouse Validation

json
{
  "warehouse_id": 99999
}
// ❌ Error: Selected warehouse does not exist

Warehouse must exist (if specified).

3. Counted Quantity Validation

json
{
  "counted_quantity": -5
}
// ❌ Error: Counted quantity cannot be negative

{
  "counted_quantity": "abc"
}
// ❌ Error: Counted quantity must be a whole number

Counted quantity must be non-negative integer (≥ 0).

4. Reserved Quantity Validation

json
{
  "product_id": 42,
  "warehouse_id": 1,
  "counted_quantity": 5
}
// Current reserved quantity: 10 units
// ❌ Error: Counted quantity cannot be less than reserved quantity.
// Reserved: 10, Counted: 5

Why?

Reserved stock represents commitments (pending orders). You cannot count fewer units than are already committed.

Example:

System Record:
- Quantity on Hand: 100 units
- Reserved: 10 units (for pending orders)
- Available: 90 units

Physical Count: 8 units ❌ Invalid
Reason: Cannot have 8 total units when 10 are already reserved

Physical Count: 12 units ✅ Valid
Result: 12 on hand, 10 reserved, 2 available

Solution:

  1. Release Reservations First:
bash
# Cancel orders or release reservations
POST /inventory/release
{
  "product_id": 42,
  "warehouse_id": 1,
  "quantity": 5
}

# Then record count
POST /inventory/physical-count
{
  "product_id": 42,
  "warehouse_id": 1,
  "counted_quantity": 5
}
  1. Count Higher Quantity:
  • Recount to ensure accuracy
  • Verify reserved quantities in system
  • Adjust count if needed

Error Responses

Validation Error (422 Unprocessable Entity):

json
{
  "message": "The given data was invalid.",
  "errors": {
    "product_id": [
      "Selected product does not exist"
    ],
    "counted_quantity": [
      "Counted quantity cannot be negative"
    ]
  }
}

Reserved Quantity Error (500 Internal Server Error):

json
{
  "message": "Counted quantity cannot be less than reserved quantity. Reserved: 10, Counted: 5"
}

Best Practices

1. Blind Counting

Don't show system quantities to counters:

Good:

Count Sheet:
Product: Laptop - Dell XPS 13
SKU: DELL-XPS13-001
Location: A-12-3

Counted Quantity: ______ (blank)

Bad:

Count Sheet:
Product: Laptop - Dell XPS 13
System Quantity: 100 units ❌ Don't show

Counted Quantity: ______ (biased toward 100)

2. Two-Person Teams

Use two-person teams for accuracy:

Counter 1 counts: 98 units
Counter 2 counts: 98 units
Match: ✅ Accept count

Counter 1 counts: 98 units
Counter 2 counts: 102 units
Mismatch: ❌ Recount

3. Schedule Strategically

Best Times:

  • After business hours
  • Weekends
  • Slow periods
  • Between receiving shipments

Avoid:

  • Peak season
  • During active receiving
  • Major sale events
  • Warehouse reorganization

4. Investigate Large Variances

Always investigate before accepting:

Variance: -20 units ($24,000 value)
Actions:
1. Recount immediately
2. Check recent transactions
3. Search warehouse thoroughly
4. Interview staff
5. Review security footage
6. Document findings

5. Document Everything

Record detailed notes:

json
{
  "product_id": 42,
  "counted_quantity": 98,
  "notes": "Counted by John Doe and Jane Smith. 2 units found damaged in receiving area, removed from inventory. Variance appears to be unreported damage."
}

6. Regular Cycle Counts

Maintain ongoing accuracy:

Weekly Cycle:

Week 1: Products 1-100
Week 2: Products 101-200
Week 3: Products 201-300
Week 4: Products 301-400
Week 5: Products 401-500

Repeat cycle

7. Root Cause Analysis

Track variance trends:

Product: Laptop - Dell XPS 13

January Count: -2 units (shrinkage)
February Count: -3 units (shrinkage)
March Count: -4 units (shrinkage)

Pattern: Consistent negative variance
Action: Investigate for theft or process issue

8. Freeze Transactions (Optional)

For critical counts, pause transactions:

1. Announce count period
2. Stop receiving/shipping
3. Complete count
4. Record counts
5. Resume operations

Not always practical, but ensures accuracy.

9. Compare Before and After

Review last count date:

json
{
  "last_counted_at": "2024-12-15T10:00:00.000000Z",
  "days_since_last_count": 32,
  "variance_trend": "improving"
}

10. Train Staff

Ensure counters understand:

  • Proper counting techniques
  • How to handle damaged goods
  • Importance of accuracy
  • Variance investigation process

Business Rules

Rule 1: System Adjustment

System always adjusts to match counted quantity:

System Before: 100 units
Counted: 98 units
System After: 98 units ✅ Always

System is the "source of truth" after count.

Rule 2: Immutable Movement Record

Physical count creates a permanent audit record that cannot be modified or deleted. The system enforces immutability to maintain regulatory compliance.

Restrictions:

  • Cannot update count movement records
  • Cannot delete count movement records
  • All count records are permanent

Solution - Create New Count:

If you need to correct a count, perform a new physical count:

bash
POST /inventory/physical-count
json
{
  "product_id": 42,
  "warehouse_id": 1,
  "counted_quantity": 97
}

Rule 3: Reserved Quantity Constraint

Cannot count less than reserved:

Reserved: 10 units
Minimum Counted: 10 units ✅
Less than 10: ❌ Invalid

Rule 4: Last Counted Timestamp

Every count updates last_counted_at:

Before Count: last_counted_at = "2024-12-15"
After Count: last_counted_at = "2025-01-16" ✅

Even if variance = 0, timestamp updates.

Rule 5: Event Dispatching

Every count triggers a system event that contains count details:

Event Data:

json
{
  "event": "InventoryCountCompleted",
  "inventory_id": 123,
  "product_id": 42,
  "warehouse_id": 1,
  "system_quantity": 100,
  "counted_quantity": 98,
  "variance": -2,
  "user_id": 5
}

Event Uses:

  • Send notifications for large variances
  • Update analytics dashboards
  • Trigger investigations
  • Log to external systems

API Endpoints

Physical Count Operations

MethodEndpointDescription
POST/inventory/physical-countRecord physical count and adjust inventory
MethodEndpointDescription
GET/inventory/show?product_id={id}View current inventory levels
GET/stock-movementsView count movements (filter by movement_type=physical_count)
GET/stock-movements/product/{productId}/historyProduct movement history

Base URL: https://api.crm.test/api/v1/operations/

Next Steps

  1. Plan Counts - Develop a counting schedule (annual, cycle, spot)
  2. Prepare Procedures - Document counting standards
  3. Train Staff - Ensure counters understand process
  4. Record Counts - Submit counted quantities via API
  5. Investigate Variances - Review and document discrepancies
  6. Improve Processes - Address root causes of variances
  7. Monitor Trends - Track accuracy improvements over time

Documentation for SynthesQ CRM/ERP Platform