Implement a new 3rd-party reading ingestion API in this Laravel codebase.

Goal:
Create a POST endpoint that allows external systems to submit meter readings into Snap & Bill without using the existing JWT user flow or CSV upload flow.

Requirements

Endpoint
- Add a new versioned API endpoint for external integrations, for example:
  POST /api/v1/integrations/readings
- Do not reuse the current admin `POST /session` endpoint directly.
- Accept/return JSON only.
GET /api/v1/integrations/readings returns all previous_readings

GET response Example

{
  "request_id": "partner-unique-id-001",
  "service_type_id": 2,
   "service_type": water,
   "service_type": water,
  "readings": [
    {
      "barcode": "ABC123456",
      "previous_unit": "452.7",
      "last_reading_date": "2026-03-25"
    }
  ]
}

Authentication and security
- Use one long-lived bearer token per site.
- Each token must map to exactly:
  - one `service_provider_id`
  - one `site_id`
- Do not implement any refresh-token mechanism.
- Store tokens hashed in DB, never plaintext after creation.
- Enforce source IP whitelist per site token.
- If token is invalid: return 401.
- If token is valid but source IP is not allowlisted: return 403.
- Use HTTPS assumptions only; no HMAC signing needed for this version.
- Add throttling/rate limiting if practical.

Scoping rules
- The backend must derive `service_provider_id` and `site_id` from the token.
- Do not trust `site_id` from the request body. Ideally do not require it in the payload at all.
- Allow `service_type_id` in the payload, but validate it against the site/provider context and optionally against token/site allowed services if such restriction is implemented.

Payload
Expected request JSON:
{
  "request_id": "partner-unique-id-001",
  "service_type_id": 2,
   "service_type": water,
  "readings": [
    {
      "barcode": "ABC123456",
      "current_unit": "452.7",
      "reading_date": "2026-03-25"
    }
  ]
}

Validation
- `request_id` is required and must be idempotent per token.
- `service_type_id` is required.
- `readings` is required and must be a non-empty array.
- Reject duplicate barcodes within the same payload.
- For each reading:
  - `barcode` required
  - `current_unit` required and numeric
  - `reading_date` required, must be valid and not in the future
- Validate barcode exists.
- Validate lot exists for derived site/provider + submitted service type + barcode.
- Validate `current_unit >= previous_unit`.
- Reuse the current session creation/update semantics where appropriate.

Processing rules
- Do not depend on a JWT-authenticated user.
- Avoid coupling to CSV parsing.
- Use logic similar to `SessionRepo::addSession()` for business validation and `OpenSession::updateOrCreate(...)`, but refactor shared logic if needed so the new endpoint is clean and maintainable.
- For `surveyor_start_by`, do not assume a human user exists. Use a safe integration/system attribution approach.
- Reuse/generate session UUID consistently for the same provider + site + service type.

Idempotency
- Implement idempotency using `(integration_token_id, request_id)` uniqueness.
- If the same request is retried with the same `request_id`, return the previous result instead of creating duplicate writes.

Response behavior
- Return machine-friendly JSON.
- Prefer per-row results and support partial success.
- Example response structure:
{
  "status": "partial_success",
  "request_id": "partner-unique-id-001",
  "accepted_count": 1,
  "rejected_count": 1,
  "results": [
    {
      "barcode": "ABC123456",
      "status": "accepted",
      "open_session_id": 4567
    },
    {
      "barcode": "ZZZ999",
      "status": "rejected",
      "code": "BARCODE_NOT_FOUND",
      "message": "Barcode does not exist"
    }
  ]
}

Persistence and audit
Create the necessary schema to support:
1. site integration tokens
- service_provider_id
- site_id
- name/client name
- token_hash
- status
- last_used_at
- optional expires_at

2. token IP whitelist
- integration token id
- ip or cidr, support 0.0.0.0/0 for testing
- status

3. ingestion request log
- integration token id
- request_id
- payload hash
- request payload or redacted snapshot
- source ip
- status
- accepted_count
- rejected_count
- response snapshot
- received_at / processed_at

4. ingestion request item log
- parent request id
- barcode
- current_unit
- reading_date
- result
- error_code
- error_message
- open_session_id if accepted

5. Management
- Scoped to super admin only
- Create API end points for Create | Revoke token



Logging
Add structured logs for (Use laravel Log facade)
- request received
- auth failure
- IP whitelist failure
- validation summary
- processing completed
- duplicate/idempotent replay detected
Do not log raw tokens.
Mask sensitive auth data in logs.

Implementation expectations
- Inspect the current codebase first and fit the implementation into existing Laravel patterns.
- Add route, middleware/auth layer, request validation, controller, service/repository logic, migrations, and any models needed.
- Refactor shared reading/session creation logic if appropriate instead of duplicating too much from `SessionRepo::addSession()`.
- Keep code consistent with the existing project style.
- Do not break existing admin/session flows.

Verification
- Add tests for:
  - valid token + valid IP + valid payload
  - invalid token
  - blocked IP
  - duplicate request_id replay
  - barcode not found
  - lot not found
  - reading below previous unit
  - duplicate barcodes in same payload
  - future reading_date
  - partial success response
- If test infrastructure is limited, still add the best feasible coverage and explain gaps.

Deliverables
- Code changes
- Migrations
- Any new middleware/models/requests/controllers/services
- Short summary of behavior
- Notes on any assumptions or follow-up work needed
