39294-vm/02_API_REFERENCE.md
2026-03-24 15:28:07 +00:00

9.6 KiB

API Reference — Swish Auto Care GMS

Backend: Node.js + Express.js

Base URL (local): http://localhost:5000/api All protected routes require: Authorization: Bearer <JWT_TOKEN> header.


Auth Routes — /api/auth

POST /api/auth/login

Public. Validates credentials, returns JWT.

Request:

{ "username": "admin", "password": "swish@2024" }

Response (200):

{ "token": "eyJhbG...", "user": { "id": 1, "username": "admin", "full_name": "Swish Admin" } }

Response (401): { "error": "Invalid credentials" }

GET /api/auth/me

Protected. Returns logged-in user info from JWT.

Response:

{ "id": 1, "username": "admin", "full_name": "Swish Admin" }

Dashboard Routes — /api/dashboard

GET /api/dashboard/today

Protected. Returns all today's summary widgets.

Response:

{
  "active_jobs": 4,
  "completed_jobs": 7,
  "today_revenue": 28500,
  "cash_balance": 14200,
  "staff_present": 3,
  "date": "24/03/2026"
}

Job Card Routes — /api/job-cards

GET /api/job-cards

Protected. List all job cards with optional filters.

Query params: ?status=active|done&date=YYYY-MM-DD&reg_no=GJ06AB1234&page=1&limit=20

Response:

{
  "data": [
    {
      "id": 1,
      "job_no": "SAC-20260324-001",
      "job_type": "full",
      "reg_no": "GJ06AB1234",
      "car_name": "Swift",
      "owner_name": "Rajesh Shah",
      "mobile_no": "9876543210",
      "service_type": "Full Detailing",
      "assigned_staff_name": "Rajan Mehta",
      "estimated_amount": 5000,
      "final_amount": null,
      "payment_mode": null,
      "status": "active",
      "job_date": "2026-03-24T10:30:00",
      "closed_at": null
    }
  ],
  "total": 1,
  "page": 1
}

POST /api/job-cards

Protected. Create a new job card.

Request (Full Job):

{
  "job_type": "full",
  "reg_no": "GJ06AB1234",
  "car_name": "Swift",
  "owner_name": "Rajesh Shah",
  "mobile_no": "9876543210",
  "service_type": "Full Detailing",
  "assigned_staff_id": 1,
  "estimated_amount": 5000,
  "notes": "Check AC vent"
}

Request (Quick Wash):

{
  "job_type": "wash",
  "reg_no": "GJ06CD5678",
  "car_name": "Creta",
  "mobile_no": "",
  "service_type": "Basic Wash",
  "assigned_staff_id": 2,
  "estimated_amount": 300
}

Response (201):

{ "id": 1, "job_no": "SAC-20260324-001", "message": "Job card created" }

GET /api/job-cards/:id

Protected. Get single job card with full details.

PUT /api/job-cards/:id

Protected. Update job card fields (only while status = 'active').

Request: Partial fields allowed.

{ "notes": "Updated notes", "estimated_amount": 5500 }

POST /api/job-cards/:id/close

Protected. Mark job as Done. Sets final_amount, payment_mode, closed_at.

Request:

{
  "final_amount": 4800,
  "payment_mode": "upi"
}

Response: { "message": "Job marked as done", "closed_at": "2026-03-24T15:45:00" }

Error if already done: { "error": "Job already closed" }


Staff Routes — /api/staff

GET /api/staff

Protected. List all staff.

Query: ?is_active=1|0

Response:

{
  "data": [
    {
      "id": 1,
      "staff_code": "SAC-STF-001",
      "full_name": "Rajan Mehta",
      "role": "Senior Detailer",
      "mobile_no": "9898989898",
      "date_of_joining": "2024-01-15",
      "monthly_salary": 18000,
      "is_active": 1
    }
  ]
}

POST /api/staff

Protected. Add new staff member. Auto-generates staff_code.

Request:

{
  "full_name": "Deepak Verma",
  "role": "Washer",
  "mobile_no": "9712345678",
  "date_of_joining": "2026-03-01",
  "monthly_salary": 13000
}

PUT /api/staff/:id

Protected. Update staff details.

PATCH /api/staff/:id/toggle

Protected. Toggle is_active status.


Attendance Routes — /api/attendance

GET /api/attendance

Protected. Get attendance for a date (default: today).

Query: ?date=YYYY-MM-DD

Response:

{
  "date": "2026-03-24",
  "records": [
    { "staff_id": 1, "staff_name": "Rajan Mehta", "status": "present" },
    { "staff_id": 2, "staff_name": "Suresh Kumar", "status": "absent" },
    { "staff_id": 3, "staff_name": "Vikram Patel", "status": null }
  ]
}

null status means not yet marked for today.

POST /api/attendance/bulk

Protected. Save attendance for multiple staff in one call.

Request:

{
  "date": "2026-03-24",
  "records": [
    { "staff_id": 1, "status": "present" },
    { "staff_id": 2, "status": "absent" },
    { "staff_id": 3, "status": "half" }
  ]
}

Response: { "message": "Attendance saved", "count": 3 }

Backend uses: INSERT INTO attendance ... ON DUPLICATE KEY UPDATE status = VALUES(status)

GET /api/attendance/summary/:staffId

Protected. Monthly attendance summary for one staff.

Query: ?month=3&year=2026

Response:

{
  "staff_id": 1,
  "month": "March 2026",
  "present": 18,
  "absent": 3,
  "half": 2,
  "records": [...]
}

Salary Routes — /api/salary

GET /api/salary

Protected. List all payments, filterable.

Query: ?staff_id=1&month=March 2026

POST /api/salary

Protected. Log a payment to a staff member.

Request:

{
  "staff_id": 1,
  "payment_date": "2026-03-24",
  "payment_month": "March 2026",
  "days_present": 22,
  "calculated_salary": 15230.77,
  "paid_amount": 15000,
  "payment_type": "salary",
  "payment_mode": "cash",
  "notes": "March salary"
}

GET /api/salary/calculate/:staffId

Protected. Auto-calculate salary based on attendance.

Query: ?month=3&year=2026

Response:

{
  "staff_id": 1,
  "staff_name": "Rajan Mehta",
  "monthly_salary": 18000,
  "days_present": 22,
  "calculated_salary": 15230.77
}

Formula: (18000 / 26) * 22 = 15230.77


Parts Routes — /api/parts

GET /api/parts

Protected. List all parts with stock info.

Query: ?category=Chemicals&low_stock=true

Response:

{
  "data": [
    {
      "id": 1,
      "part_code": "SAC-PRT-001",
      "name": "Ceramic Coat 9H",
      "category": "Chemicals",
      "unit": "bottle",
      "purchase_price": 1200,
      "selling_price": 2500,
      "stock_qty": 15,
      "low_stock_alert": 5,
      "is_low": false
    }
  ]
}

POST /api/parts

Protected. Add new part. Auto-generates part_code.

PUT /api/parts/:id

Protected. Update part details (not stock — stock changes via sales).

PATCH /api/parts/:id/stock

Protected. Manual stock adjustment (restock).

Request: { "adjustment": 10, "reason": "New stock received" }


Parts Sales Routes — /api/parts-sales

GET /api/parts-sales

Protected. List all sales.

Query: ?date=YYYY-MM-DD&job_card_id=5

POST /api/parts-sales

Protected. Record a parts sale. Auto-deducts stock.

Request:

{
  "part_id": 1,
  "job_card_id": null,
  "quantity": 2,
  "unit_price": 2500,
  "total_amount": 5000,
  "customer_name": "Ankit Patel",
  "payment_mode": "upi"
}

Backend must:

  1. Verify stock_qty >= quantity. If not: { "error": "Insufficient stock" }
  2. Insert into parts_sales
  3. UPDATE parts SET stock_qty = stock_qty - ? WHERE id = ?
  4. Return sale record

Cash Ledger Routes — /api/cash-ledger

GET /api/cash-ledger

Protected. List entries with optional date filter.

Query: ?from=YYYY-MM-DD&to=YYYY-MM-DD&type=in|out

POST /api/cash-ledger

Protected. Add cash in or out entry.

Request:

{
  "entry_type": "out",
  "amount": 500,
  "category": "Utilities",
  "description": "Electricity bill payment"
}

Accounts Routes — /api/accounts

GET /api/accounts/summary

Protected. Consolidated financial summary.

Query: ?from=YYYY-MM-DD&to=YYYY-MM-DD (default: today)

Response:

{
  "period": { "from": "2026-03-24", "to": "2026-03-24" },
  "income": {
    "job_revenue": 28500,
    "parts_revenue": 7500,
    "cash_in_other": 2000,
    "total": 38000
  },
  "expense": {
    "staff_payments": 15000,
    "cash_out_other": 800,
    "total": 15800
  },
  "net_balance": 22200
}

GET /api/accounts/transactions

Protected. All transactions in a date range (for drill-down).

Returns unified list of all financial movements with source type tag.


Reports Routes — /api/reports

GET /api/reports/daily

Protected. Get daily report data (JSON, for on-screen preview).

Query: ?date=YYYY-MM-DD (default: today)

GET /api/reports/daily/download

Protected. Download daily report as .xlsx file.

Query: ?date=YYYY-MM-DD

Response: Binary .xlsx stream with headers:

Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="SwishGMS_DailyReport_24-03-2026.xlsx"

Export Routes — /api/exports

GET /api/exports/job-cards

Protected. Export all job cards as .xlsx.

Query: ?from=YYYY-MM-DD&to=YYYY-MM-DD

GET /api/exports/staff-attendance

Protected. Export staff + attendance as .xlsx.

Query: ?month=3&year=2026

GET /api/exports/parts-inventory

Protected. Export parts inventory as .xlsx.

GET /api/exports/accounts

Protected. Export accounts/transactions as .xlsx.

Query: ?from=YYYY-MM-DD&to=YYYY-MM-DD


Error Response Format (Consistent Across All Routes)

{ "error": "Human-readable error message", "code": "OPTIONAL_ERROR_CODE" }

HTTP status codes used:

  • 200 OK
  • 201 Created
  • 400 Bad Request (validation errors)
  • 401 Unauthorized (missing/invalid JWT)
  • 403 Forbidden
  • 404 Not Found
  • 409 Conflict (e.g. duplicate attendance)
  • 500 Internal Server Error