# Admin — Upload Signed Contract Document

Attaches a scanned/signed contract document to an existing contract, as an
archival record. This does **not** change the contract's `status` — it's
independent of the sign/approve/reject/terminate workflow.

The upload is a two-step flow: upload the file to the shared media endpoint
first, then attach it to the contract by its `hash`.

---

## Step 1 — Upload the file

```
POST /media
Authorization: Bearer {admin_token}
Content-Type: multipart/form-data
```

Note: unlike every other endpoint in this API, this route is **not** under
the `/api/v1/` prefix — it's mounted at the bare root by the Media module's
own service provider (`modules/Media/src/MediaServiceProvider.php`), so the
full URL is `{base_url}/media`, not `{base_url}/api/v1/media`.

| Field          | Type   | Required | Notes                                                                                              |
| -------------- | ------ | -------- | -------------------------------------------------------------------------------------------------- |
| `file`       | file   | yes      | Max 10MB. Allowed: jpg, jpeg, png, gif, webp,**pdf**, avi, mov, wmv, flv, mkv, mp4, mp3, wav |
| `collection` | string | no       | Optional free-text label, not required for this flow                                               |

**Response `201`:**

```json
{
  "status": "success",
  "message": "Media uploaded successfully",
  "data": {
    "id": 123,
    "hash": "9f8a1c...e4",
    "url": "https://.../storage/media/9f8a1c...e4.pdf",
    "mime_type": "application/pdf",
    "size": 245678,
    "original_name": "contract-signed.pdf"
  }
}
```

Keep the `hash` from this response — it's what step 2 needs (not `id`).

At this point the file is uploaded but marked temporary (`is_temp = true`)
and not yet linked to any contract; it gets attached in step 2.

---

## Step 2 — Attach it to the contract

```
POST /api/v1/admin/contracts/{id}/signed-document
Authorization: Bearer {admin_token}
Content-Type: application/json
```

| Path param | Type | Notes             |
| ---------- | ---- | ----------------- |
| `id`     | int  | The contract's ID |

| Body field          | Type   | Required | Notes                                                   |
| ------------------- | ------ | -------- | ------------------------------------------------------- |
| `signed_document` | string | yes      | The`hash` returned by step 1 (not the numeric `id`) |

**Request body:**

```json
{
  "signed_document": "9f8a1c...e4"
}
```

### Success — `200`

```json
{
  "status": "success",
  "message": "Signed contract document uploaded successfully.",
  "data": {
    "id": 45,
    "contract_number": "CTR-2026-000045",
    "status": "active",
    "signed_pdf_path": "https://.../storage/media/9f8a1c...e4.pdf",
    "signatures": [
      {
        "id": 12,
        "signer_type": "admin",
        "url": "https://.../storage/media/9f8a1c...e4.pdf",
        "signed_at": "2026-09-09T10:15:00+00:00"
      }
    ],
    "...": "rest of the contract object — see full shape below"
  }
}
```

`status` is unchanged from whatever it was before the call.

The full `data` object is the same contract-details shape returned by
`GET /api/v1/admin/contracts/{id}` (company, dates, branches, services,
signatures, renewal_requests, etc.) — see **Full response shape** below.

### Validation error — `422`

The `signed_document` field fails validation when:

- it's missing
- the hash doesn't match any uploaded media
- that media is already attached to a **different** record
- the media's mime type isn't `image/*` or `application/*`
- the physical file is missing from storage

```json
{
  "status": "fail",
  "message": "The signed document field is invalid.",
  "errors": {
    "signed_document": ["The media file was not found."]
  }
}
```

(Laravel's standard validation-error envelope — exact message varies by cause.)

### Not found — `404`

If `{id}` doesn't match an existing contract.

---

## Full response shape (`data`)

```json
{
  "id": 45,
  "contract_number": "CTR-2026-000045",
  "company": { "id": 10, "name": "Acme Co.", "email": "acme@example.com" },
  "created_by": { "id": 2, "name": "Admin User" },
  "approved_by": { "id": 2, "name": "Admin User" },
  "signed_by": { "id": 10, "name": "Acme Co." },
  "start_date": "2026-01-01",
  "end_date": "2026-12-31",
  "billing_cycle": "monthly",
  "visits_allowed": 24,
  "visits_consumed": 3,
  "remaining_visits": 21,
  "total_amount": "12000.00",
  "currency": "SAR",
  "status": "active",
  "status_label": "Active",
  "auto_renew": true,
  "pdf_path": null,
  "signed_pdf_path": "https://.../storage/media/9f8a1c...e4.pdf",
  "signed_at": "2026-01-02T09:00:00+00:00",
  "approved_at": "2026-01-02T09:30:00+00:00",
  "terminated_at": null,
  "terminated_reason": null,
  "notes": null,
  "branches": [{ "id": 3, "name": "Riyadh Branch" }],
  "services": [{ "id": 7, "name": "AC Maintenance" }],
  "signatures": [
    { "id": 11, "signer_type": "company", "url": "https://.../storage/media/aa11bb...cc.pdf", "signed_at": "2026-01-02T09:00:00+00:00" },
    { "id": 12, "signer_type": "admin", "url": "https://.../storage/media/9f8a1c...e4.pdf", "signed_at": "2026-09-09T10:15:00+00:00" }
  ],
  "renewal_requests": [],
  "created_at": "2026-01-01T08:00:00+00:00",
  "updated_at": "2026-09-09T10:15:00+00:00"
}
```

---

## Notes for frontend

- This can be called **regardless of contract status** — it's a
  document-attach action, not a workflow transition.
- Calling it again with a new `signed_document` replaces `signed_pdf_path`
  and adds another entry to `signatures` (it does not delete the previous
  media/history).
- `signatures[].signer_type` distinguishes who attached the document —
  `"company"` (from the company's own sign step) vs `"admin"` (this
  endpoint).
