fix invoice informations

This commit is contained in:
2026-04-16 11:42:11 +03:00
parent 973149e974
commit f17dd1486c
20 changed files with 2579 additions and 178 deletions
+882 -18
View File
@@ -462,8 +462,8 @@
],
"summary": "GET /api/profile",
"responses": {
"200": {
"description": "OK",
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
@@ -21668,6 +21668,290 @@
}
},
"/api/estimates/{id}": {
"get": {
"tags": [
"Estimates"
],
"summary": "Display the specified estimate.",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"title": {
"type": "string"
},
"customer_id": {
"type": "integer"
},
"vehicle_id": {
"type": "integer"
},
"department_id": {
"type": "integer"
},
"estimate_number": {
"type": "string"
},
"date": {
"type": "string"
},
"has_insurance": {
"type": "boolean"
},
"enable_digital_authorisation": {
"type": "boolean"
},
"insurance_type_id": {
"type": "integer"
},
"insurer_id": {
"type": "integer"
},
"service_writer_id": {
"type": "integer"
},
"footer": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"updated_at": {
"type": "string",
"format": "date-time"
},
"labels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"title": {
"type": "string"
},
"color_code": {
"type": "string"
},
"pivot": {
"type": "object",
"properties": {
"estimate_id": {
"type": "integer"
},
"label_id": {
"type": "integer"
}
}
}
}
}
},
"customer_remarks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"estimate_id": {
"type": "integer"
},
"remark": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"updated_at": {
"type": "string",
"format": "date-time"
}
}
}
},
"customer": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
}
}
},
"vehicle": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"registration_number": {
"type": "string"
},
"make": {
"type": "string"
},
"model": {
"type": "string"
}
}
},
"department": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
},
"insurance_type": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"title": {
"type": "string"
}
}
},
"insurer": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
}
}
},
"service_writer": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
}
}
}
}
}
}
},
"example": {
"data": {
"id": 1,
"title": "Estimate for Toyota Camry",
"customer_id": 1,
"vehicle_id": 1,
"department_id": 1,
"estimate_number": "EST-001",
"date": "2026-03-31",
"has_insurance": false,
"enable_digital_authorisation": false,
"insurance_type_id": 1,
"insurer_id": 2,
"service_writer_id": 1,
"footer": "Thank you for your business.",
"created_at": "2026-03-31T10:00:00.000000Z",
"updated_at": "2026-03-31T10:00:00.000000Z",
"labels": [
{
"id": 1,
"title": "Urgent",
"color_code": "#FF0000",
"pivot": {
"estimate_id": 1,
"label_id": 1
}
}
],
"customer_remarks": [
{
"id": 1,
"estimate_id": 1,
"remark": "Oil change recommended.",
"created_at": "2026-03-31T10:00:00.000000Z",
"updated_at": "2026-03-31T10:00:00.000000Z"
}
],
"customer": {
"id": 1,
"first_name": "John",
"last_name": "Doe"
},
"vehicle": {
"id": 1,
"registration_number": "ABC-1234",
"make": "Toyota",
"model": "Camry"
},
"department": {
"id": 1,
"name": "Service"
},
"insurance_type": {
"id": 1,
"title": "Comprehensive"
},
"insurer": {
"id": 2,
"first_name": "Alex",
"last_name": "Insurer"
},
"service_writer": {
"id": 1,
"first_name": "Sam",
"last_name": "Writer"
}
}
}
}
}
}
}
},
"put": {
"tags": [
"Estimates"
@@ -42973,6 +43257,24 @@
"estimate_id": {
"type": "integer"
},
"kms_in": {
"type": "integer"
},
"has_insurance": {
"type": "boolean"
},
"insurer_id": {
"type": "integer"
},
"invoice_to_id": {
"type": "integer"
},
"billing_address_id": {
"type": "integer"
},
"delivery_address_id": {
"type": "integer"
},
"invoice_date": {
"type": "string"
},
@@ -42988,17 +43290,195 @@
"invoice_number": {
"type": "string"
},
"invoice_title": {
"type": "string"
},
"department_id": {
"type": "integer"
},
"notes": {
"type": "string"
},
"terms_and_conditions": {
"type": "string"
},
"status": {
"type": "string"
},
"received_payment": {
"type": "boolean"
},
"payment_mode_id": {
"type": "integer"
},
"deposit_to": {
"type": "string"
},
"amount": {
"type": "integer"
},
"discount": {
"type": "string"
},
"inspection_categories": {
"type": "array",
"items": {
"type": "object",
"properties": {
"inspection_category_id": {
"type": "integer"
},
"rate_type": {
"type": "string"
},
"labor_rate": {
"type": "integer"
},
"working_hours": {
"type": "integer"
},
"labor_hours": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
},
"parts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"part_id": {
"type": "integer"
},
"quantity": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
},
"expenses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"expense_id": {
"type": "integer"
},
"quantity": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
},
"services": {
"type": "array",
"items": {
"type": "object",
"properties": {
"service_id": {
"type": "integer"
},
"rate_type": {
"type": "string"
},
"labor_rate_id": {
"type": "integer"
},
"working_hours": {
"type": "integer"
},
"labor_hours": {
"type": "integer"
},
"quantity": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
},
"service_groups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"service_group_id": {
"type": "integer"
},
"rate_type": {
"type": "string"
},
"labor_rate_id": {
"type": "integer"
},
"working_hours": {
"type": "integer"
},
"labor_hours": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
}
}
},
@@ -43007,22 +43487,94 @@
"customer_id": 1,
"vehicle_id": 1,
"estimate_id": 1,
"kms_in": 50000,
"has_insurance": false,
"insurer_id": 2,
"invoice_to_id": 1,
"billing_address_id": 10,
"delivery_address_id": 11,
"invoice_date": "2026-03-31",
"due_date": "2026-04-14",
"payment_terms_id": 1,
"invoice_sequence_id": 1,
"invoice_number": "INV-001",
"invoice_title": "Tax Invoice",
"department_id": 1,
"notes": "string",
"notes": "Vehicle service and parts",
"terms_and_conditions": "Payment due in 14 days.",
"status": "draft",
"discount": "no"
"received_payment": false,
"payment_mode_id": 1,
"deposit_to": "Main Account",
"amount": 2500,
"discount": "no",
"inspection_categories": [
{
"inspection_category_id": 1,
"rate_type": "flat_rate",
"labor_rate": 500,
"working_hours": 1,
"labor_hours": 1,
"rate": 500,
"chart_of_account": "4000",
"description": "General inspection",
"department_id": 1
}
],
"parts": [
{
"part_id": 1,
"quantity": 2,
"rate": 150,
"chart_of_account": "4100",
"description": "Oil filter",
"department_id": 1
}
],
"expenses": [
{
"expense_id": 1,
"quantity": 1,
"rate": 100,
"chart_of_account": "4200",
"description": "Shop supplies",
"department_id": 1
}
],
"services": [
{
"service_id": 1,
"rate_type": "hourly",
"labor_rate_id": 1,
"working_hours": 2,
"labor_hours": 2,
"quantity": 1,
"rate": 800,
"chart_of_account": "4300",
"description": "Engine service",
"department_id": 1
}
],
"service_groups": [
{
"service_group_id": 1,
"rate_type": "flat_rate",
"labor_rate_id": 1,
"working_hours": 1,
"labor_hours": 1,
"rate": 600,
"chart_of_account": "4400",
"description": "Major service package",
"department_id": 1
}
]
}
}
}
},
"responses": {
"200": {
"description": "OK",
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
@@ -43098,7 +43650,7 @@
"type": "string"
},
"received_payment": {
"type": "integer"
"type": "boolean"
},
"payment_mode_id": {
"type": "integer"
@@ -43119,25 +43671,253 @@
"updated_at": {
"type": "string",
"format": "date-time"
},
"customer": {
"type": "object",
"properties": {
"id": {
"type": "integer"
}
}
},
"vehicle": {
"type": "object",
"properties": {
"id": {
"type": "integer"
}
}
},
"invoice_sequence": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"title": {
"type": "string"
}
}
},
"department": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
},
"invoice_inspection_categories": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"invoice_id": {
"type": "integer"
},
"inspection_category_id": {
"type": "integer"
},
"rate_type": {
"type": "string"
},
"labor_rate": {
"type": "integer"
},
"working_hours": {
"type": "integer"
},
"labor_hours": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
},
"invoice_parts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"invoice_id": {
"type": "integer"
},
"part_id": {
"type": "integer"
},
"quantity": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
},
"invoice_expenses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"invoice_id": {
"type": "integer"
},
"expense_id": {
"type": "integer"
},
"quantity": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
},
"invoice_services": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"invoice_id": {
"type": "integer"
},
"service_id": {
"type": "integer"
},
"rate_type": {
"type": "string"
},
"labor_rate_id": {
"type": "integer"
},
"working_hours": {
"type": "integer"
},
"labor_hours": {
"type": "integer"
},
"quantity": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
},
"invoice_service_groups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer"
},
"invoice_id": {
"type": "integer"
},
"service_group_id": {
"type": "integer"
},
"rate_type": {
"type": "string"
},
"labor_rate_id": {
"type": "integer"
},
"working_hours": {
"type": "integer"
},
"labor_hours": {
"type": "integer"
},
"rate": {
"type": "integer"
},
"chart_of_account": {
"type": "string"
},
"description": {
"type": "string"
},
"department_id": {
"type": "integer"
}
}
}
}
}
}
}
},
"example": {
"message": "Operation completed successfully.",
"message": "Invoice created successfully.",
"data": {
"id": 1,
"subject": "Invoice for Job Card 001",
"subject": "Invoice for Service",
"customer_id": 1,
"vehicle_id": 1,
"estimate_id": 1,
"kms_in": 50000,
"has_insurance": false,
"insurer_id": 1,
"insurer_id": 2,
"invoice_to_id": 1,
"billing_address_id": 1,
"delivery_address_id": 1,
"billing_address_id": 10,
"delivery_address_id": 11,
"invoice_date": "2026-03-31",
"due_date": "2026-04-14",
"payment_terms_id": 1,
@@ -43145,16 +43925,100 @@
"invoice_number": "INV-001",
"invoice_title": "Tax Invoice",
"department_id": 1,
"notes": "string",
"terms_and_conditions": "string",
"notes": "Vehicle service and parts",
"terms_and_conditions": "Payment due in 14 days.",
"status": "draft",
"received_payment": 0,
"received_payment": false,
"payment_mode_id": 1,
"deposit_to": "string",
"amount": 0,
"deposit_to": "Main Account",
"amount": 2500,
"discount": "no",
"created_at": "2026-03-31T10:00:00.000000Z",
"updated_at": "2026-03-31T10:00:00.000000Z"
"updated_at": "2026-03-31T10:00:00.000000Z",
"customer": {
"id": 1
},
"vehicle": {
"id": 1
},
"invoice_sequence": {
"id": 1,
"title": "INV"
},
"department": {
"id": 1,
"name": "Service"
},
"invoice_inspection_categories": [
{
"id": 1,
"invoice_id": 1,
"inspection_category_id": 1,
"rate_type": "flat_rate",
"labor_rate": 500,
"working_hours": 1,
"labor_hours": 1,
"rate": 500,
"chart_of_account": "4000",
"description": "General inspection",
"department_id": 1
}
],
"invoice_parts": [
{
"id": 1,
"invoice_id": 1,
"part_id": 1,
"quantity": 2,
"rate": 150,
"chart_of_account": "4100",
"description": "Oil filter",
"department_id": 1
}
],
"invoice_expenses": [
{
"id": 1,
"invoice_id": 1,
"expense_id": 1,
"quantity": 1,
"rate": 100,
"chart_of_account": "4200",
"description": "Shop supplies",
"department_id": 1
}
],
"invoice_services": [
{
"id": 1,
"invoice_id": 1,
"service_id": 1,
"rate_type": "hourly",
"labor_rate_id": 1,
"working_hours": 2,
"labor_hours": 2,
"quantity": 1,
"rate": 800,
"chart_of_account": "4300",
"description": "Engine service",
"department_id": 1
}
],
"invoice_service_groups": [
{
"id": 1,
"invoice_id": 1,
"service_group_id": 1,
"rate_type": "flat_rate",
"labor_rate_id": 1,
"working_hours": 1,
"labor_hours": 1,
"rate": 600,
"chart_of_account": "4400",
"description": "Major service package",
"department_id": 1
}
]
}
}
}
+8 -3
View File
@@ -23,7 +23,8 @@
"check-types": "echo \"No typecheck configured for @garage/api\""
},
"dependencies": {
"openapi-fetch": "^0.14.0"
"openapi-fetch": "^0.14.0",
"pino": "^10.3.1"
},
"devDependencies": {
"openapi-typescript": "^7.10.1"
@@ -33,7 +34,11 @@
"server-only": "*"
},
"peerDependenciesMeta": {
"next": { "optional": true },
"server-only": { "optional": true }
"next": {
"optional": true
},
"server-only": {
"optional": true
}
}
}
+97 -10
View File
@@ -1,6 +1,6 @@
{
"info": {
"_postman_id": "351b2d30-cb82-4904-9a47-0d356181a8ea",
"_postman_id": "38ac2be3-7ab6-4dcc-ad76-6112212395af",
"name": "Reparee Collection",
"description": "Auto-generated from OpenAPI spec. Import storage/app/openapi-default.json for the full schema.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
@@ -135,7 +135,7 @@
},
"response": [
{
"name": "200 OK",
"name": "201 Created",
"originalRequest": {
"auth": {
"type": "bearer",
@@ -169,8 +169,8 @@
]
}
},
"status": "OK",
"code": 200,
"status": "Created",
"code": 201,
"_postman_previewlanguage": "json",
"header": [
{
@@ -14953,6 +14953,93 @@
}
]
},
{
"name": "Display the specified estimate.",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{auth_token}}",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"url": {
"raw": "{{base_url}}/api/estimates/{{id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"estimates",
"{{id}}"
]
}
},
"response": [
{
"name": "200 OK",
"originalRequest": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{auth_token}}",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"url": {
"raw": "{{base_url}}/api/estimates/{{id}}",
"host": [
"{{base_url}}"
],
"path": [
"api",
"estimates",
"{{id}}"
]
}
},
"status": "OK",
"code": 200,
"_postman_previewlanguage": "json",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"cookie": [],
"body": "{\n \"data\": {\n \"id\": 1,\n \"title\": \"Estimate for Toyota Camry\",\n \"customer_id\": 1,\n \"vehicle_id\": 1,\n \"department_id\": 1,\n \"estimate_number\": \"EST-001\",\n \"date\": \"2026-03-31\",\n \"has_insurance\": false,\n \"enable_digital_authorisation\": false,\n \"insurance_type_id\": 1,\n \"insurer_id\": 2,\n \"service_writer_id\": 1,\n \"footer\": \"Thank you for your business.\",\n \"created_at\": \"2026-03-31T10:00:00.000000Z\",\n \"updated_at\": \"2026-03-31T10:00:00.000000Z\",\n \"labels\": [\n {\n \"id\": 1,\n \"title\": \"Urgent\",\n \"color_code\": \"#FF0000\",\n \"pivot\": {\n \"estimate_id\": 1,\n \"label_id\": 1\n }\n }\n ],\n \"customer_remarks\": [\n {\n \"id\": 1,\n \"estimate_id\": 1,\n \"remark\": \"Oil change recommended.\",\n \"created_at\": \"2026-03-31T10:00:00.000000Z\",\n \"updated_at\": \"2026-03-31T10:00:00.000000Z\"\n }\n ],\n \"customer\": {\n \"id\": 1,\n \"first_name\": \"John\",\n \"last_name\": \"Doe\"\n },\n \"vehicle\": {\n \"id\": 1,\n \"registration_number\": \"ABC-1234\",\n \"make\": \"Toyota\",\n \"model\": \"Camry\"\n },\n \"department\": {\n \"id\": 1,\n \"name\": \"Service\"\n },\n \"insurance_type\": {\n \"id\": 1,\n \"title\": \"Comprehensive\"\n },\n \"insurer\": {\n \"id\": 2,\n \"first_name\": \"Alex\",\n \"last_name\": \"Insurer\"\n },\n \"service_writer\": {\n \"id\": 1,\n \"first_name\": \"Sam\",\n \"last_name\": \"Writer\"\n }\n }\n}"
}
]
},
{
"name": "Store a newly created estimate.",
"request": {
@@ -33569,7 +33656,7 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"subject\": \"Invoice for Service\",\n \"customer_id\": 1,\n \"vehicle_id\": 1,\n \"estimate_id\": 1,\n \"invoice_date\": \"2026-03-31\",\n \"due_date\": \"2026-04-14\",\n \"payment_terms_id\": 1,\n \"invoice_sequence_id\": 1,\n \"invoice_number\": \"INV-001\",\n \"department_id\": 1,\n \"notes\": \"string\",\n \"status\": \"draft\",\n \"discount\": \"no\"\n}",
"raw": "{\n \"subject\": \"Invoice for Service\",\n \"customer_id\": 1,\n \"vehicle_id\": 1,\n \"estimate_id\": 1,\n \"kms_in\": 50000,\n \"has_insurance\": false,\n \"insurer_id\": 2,\n \"invoice_to_id\": 1,\n \"billing_address_id\": 10,\n \"delivery_address_id\": 11,\n \"invoice_date\": \"2026-03-31\",\n \"due_date\": \"2026-04-14\",\n \"payment_terms_id\": 1,\n \"invoice_sequence_id\": 1,\n \"invoice_number\": \"INV-001\",\n \"invoice_title\": \"Tax Invoice\",\n \"department_id\": 1,\n \"notes\": \"Vehicle service and parts\",\n \"terms_and_conditions\": \"Payment due in 14 days.\",\n \"status\": \"draft\",\n \"received_payment\": false,\n \"payment_mode_id\": 1,\n \"deposit_to\": \"Main Account\",\n \"amount\": 2500,\n \"discount\": \"no\",\n \"inspection_categories\": [\n {\n \"inspection_category_id\": 1,\n \"rate_type\": \"flat_rate\",\n \"labor_rate\": 500,\n \"working_hours\": 1,\n \"labor_hours\": 1,\n \"rate\": 500,\n \"chart_of_account\": \"4000\",\n \"description\": \"General inspection\",\n \"department_id\": 1\n }\n ],\n \"parts\": [\n {\n \"part_id\": 1,\n \"quantity\": 2,\n \"rate\": 150,\n \"chart_of_account\": \"4100\",\n \"description\": \"Oil filter\",\n \"department_id\": 1\n }\n ],\n \"expenses\": [\n {\n \"expense_id\": 1,\n \"quantity\": 1,\n \"rate\": 100,\n \"chart_of_account\": \"4200\",\n \"description\": \"Shop supplies\",\n \"department_id\": 1\n }\n ],\n \"services\": [\n {\n \"service_id\": 1,\n \"rate_type\": \"hourly\",\n \"labor_rate_id\": 1,\n \"working_hours\": 2,\n \"labor_hours\": 2,\n \"quantity\": 1,\n \"rate\": 800,\n \"chart_of_account\": \"4300\",\n \"description\": \"Engine service\",\n \"department_id\": 1\n }\n ],\n \"service_groups\": [\n {\n \"service_group_id\": 1,\n \"rate_type\": \"flat_rate\",\n \"labor_rate_id\": 1,\n \"working_hours\": 1,\n \"labor_hours\": 1,\n \"rate\": 600,\n \"chart_of_account\": \"4400\",\n \"description\": \"Major service package\",\n \"department_id\": 1\n }\n ]\n}",
"options": {
"raw": {
"language": "json"
@@ -33589,7 +33676,7 @@
},
"response": [
{
"name": "200 OK",
"name": "201 Created",
"originalRequest": {
"auth": {
"type": "bearer",
@@ -33614,7 +33701,7 @@
],
"body": {
"mode": "raw",
"raw": "{\n \"subject\": \"Invoice for Service\",\n \"customer_id\": 1,\n \"vehicle_id\": 1,\n \"estimate_id\": 1,\n \"invoice_date\": \"2026-03-31\",\n \"due_date\": \"2026-04-14\",\n \"payment_terms_id\": 1,\n \"invoice_sequence_id\": 1,\n \"invoice_number\": \"INV-001\",\n \"department_id\": 1,\n \"notes\": \"string\",\n \"status\": \"draft\",\n \"discount\": \"no\"\n}",
"raw": "{\n \"subject\": \"Invoice for Service\",\n \"customer_id\": 1,\n \"vehicle_id\": 1,\n \"estimate_id\": 1,\n \"kms_in\": 50000,\n \"has_insurance\": false,\n \"insurer_id\": 2,\n \"invoice_to_id\": 1,\n \"billing_address_id\": 10,\n \"delivery_address_id\": 11,\n \"invoice_date\": \"2026-03-31\",\n \"due_date\": \"2026-04-14\",\n \"payment_terms_id\": 1,\n \"invoice_sequence_id\": 1,\n \"invoice_number\": \"INV-001\",\n \"invoice_title\": \"Tax Invoice\",\n \"department_id\": 1,\n \"notes\": \"Vehicle service and parts\",\n \"terms_and_conditions\": \"Payment due in 14 days.\",\n \"status\": \"draft\",\n \"received_payment\": false,\n \"payment_mode_id\": 1,\n \"deposit_to\": \"Main Account\",\n \"amount\": 2500,\n \"discount\": \"no\",\n \"inspection_categories\": [\n {\n \"inspection_category_id\": 1,\n \"rate_type\": \"flat_rate\",\n \"labor_rate\": 500,\n \"working_hours\": 1,\n \"labor_hours\": 1,\n \"rate\": 500,\n \"chart_of_account\": \"4000\",\n \"description\": \"General inspection\",\n \"department_id\": 1\n }\n ],\n \"parts\": [\n {\n \"part_id\": 1,\n \"quantity\": 2,\n \"rate\": 150,\n \"chart_of_account\": \"4100\",\n \"description\": \"Oil filter\",\n \"department_id\": 1\n }\n ],\n \"expenses\": [\n {\n \"expense_id\": 1,\n \"quantity\": 1,\n \"rate\": 100,\n \"chart_of_account\": \"4200\",\n \"description\": \"Shop supplies\",\n \"department_id\": 1\n }\n ],\n \"services\": [\n {\n \"service_id\": 1,\n \"rate_type\": \"hourly\",\n \"labor_rate_id\": 1,\n \"working_hours\": 2,\n \"labor_hours\": 2,\n \"quantity\": 1,\n \"rate\": 800,\n \"chart_of_account\": \"4300\",\n \"description\": \"Engine service\",\n \"department_id\": 1\n }\n ],\n \"service_groups\": [\n {\n \"service_group_id\": 1,\n \"rate_type\": \"flat_rate\",\n \"labor_rate_id\": 1,\n \"working_hours\": 1,\n \"labor_hours\": 1,\n \"rate\": 600,\n \"chart_of_account\": \"4400\",\n \"description\": \"Major service package\",\n \"department_id\": 1\n }\n ]\n}",
"options": {
"raw": {
"language": "json"
@@ -33632,8 +33719,8 @@
]
}
},
"status": "OK",
"code": 200,
"status": "Created",
"code": 201,
"_postman_previewlanguage": "json",
"header": [
{
@@ -33642,7 +33729,7 @@
}
],
"cookie": [],
"body": "{\n \"message\": \"Operation completed successfully.\",\n \"data\": {\n \"id\": 1,\n \"subject\": \"Invoice for Job Card 001\",\n \"customer_id\": 1,\n \"vehicle_id\": 1,\n \"estimate_id\": 1,\n \"kms_in\": 50000,\n \"has_insurance\": false,\n \"insurer_id\": 1,\n \"invoice_to_id\": 1,\n \"billing_address_id\": 1,\n \"delivery_address_id\": 1,\n \"invoice_date\": \"2026-03-31\",\n \"due_date\": \"2026-04-14\",\n \"payment_terms_id\": 1,\n \"invoice_sequence_id\": 1,\n \"invoice_number\": \"INV-001\",\n \"invoice_title\": \"Tax Invoice\",\n \"department_id\": 1,\n \"notes\": \"string\",\n \"terms_and_conditions\": \"string\",\n \"status\": \"draft\",\n \"received_payment\": 0,\n \"payment_mode_id\": 1,\n \"deposit_to\": \"string\",\n \"amount\": 0,\n \"discount\": \"no\",\n \"created_at\": \"2026-03-31T10:00:00.000000Z\",\n \"updated_at\": \"2026-03-31T10:00:00.000000Z\"\n }\n}"
"body": "{\n \"message\": \"Invoice created successfully.\",\n \"data\": {\n \"id\": 1,\n \"subject\": \"Invoice for Service\",\n \"customer_id\": 1,\n \"vehicle_id\": 1,\n \"estimate_id\": 1,\n \"kms_in\": 50000,\n \"has_insurance\": false,\n \"insurer_id\": 2,\n \"invoice_to_id\": 1,\n \"billing_address_id\": 10,\n \"delivery_address_id\": 11,\n \"invoice_date\": \"2026-03-31\",\n \"due_date\": \"2026-04-14\",\n \"payment_terms_id\": 1,\n \"invoice_sequence_id\": 1,\n \"invoice_number\": \"INV-001\",\n \"invoice_title\": \"Tax Invoice\",\n \"department_id\": 1,\n \"notes\": \"Vehicle service and parts\",\n \"terms_and_conditions\": \"Payment due in 14 days.\",\n \"status\": \"draft\",\n \"received_payment\": false,\n \"payment_mode_id\": 1,\n \"deposit_to\": \"Main Account\",\n \"amount\": 2500,\n \"discount\": \"no\",\n \"created_at\": \"2026-03-31T10:00:00.000000Z\",\n \"updated_at\": \"2026-03-31T10:00:00.000000Z\",\n \"customer\": {\n \"id\": 1\n },\n \"vehicle\": {\n \"id\": 1\n },\n \"invoice_sequence\": {\n \"id\": 1,\n \"title\": \"INV\"\n },\n \"department\": {\n \"id\": 1,\n \"name\": \"Service\"\n },\n \"invoice_inspection_categories\": [\n {\n \"id\": 1,\n \"invoice_id\": 1,\n \"inspection_category_id\": 1,\n \"rate_type\": \"flat_rate\",\n \"labor_rate\": 500,\n \"working_hours\": 1,\n \"labor_hours\": 1,\n \"rate\": 500,\n \"chart_of_account\": \"4000\",\n \"description\": \"General inspection\",\n \"department_id\": 1\n }\n ],\n \"invoice_parts\": [\n {\n \"id\": 1,\n \"invoice_id\": 1,\n \"part_id\": 1,\n \"quantity\": 2,\n \"rate\": 150,\n \"chart_of_account\": \"4100\",\n \"description\": \"Oil filter\",\n \"department_id\": 1\n }\n ],\n \"invoice_expenses\": [\n {\n \"id\": 1,\n \"invoice_id\": 1,\n \"expense_id\": 1,\n \"quantity\": 1,\n \"rate\": 100,\n \"chart_of_account\": \"4200\",\n \"description\": \"Shop supplies\",\n \"department_id\": 1\n }\n ],\n \"invoice_services\": [\n {\n \"id\": 1,\n \"invoice_id\": 1,\n \"service_id\": 1,\n \"rate_type\": \"hourly\",\n \"labor_rate_id\": 1,\n \"working_hours\": 2,\n \"labor_hours\": 2,\n \"quantity\": 1,\n \"rate\": 800,\n \"chart_of_account\": \"4300\",\n \"description\": \"Engine service\",\n \"department_id\": 1\n }\n ],\n \"invoice_service_groups\": [\n {\n \"id\": 1,\n \"invoice_id\": 1,\n \"service_group_id\": 1,\n \"rate_type\": \"flat_rate\",\n \"labor_rate_id\": 1,\n \"working_hours\": 1,\n \"labor_hours\": 1,\n \"rate\": 600,\n \"chart_of_account\": \"4400\",\n \"description\": \"Major service package\",\n \"department_id\": 1\n }\n ]\n }\n}"
}
]
},
+4 -4
View File
@@ -1,6 +1,6 @@
import { CrudClient } from "../infra/crud-client"
import type { ApiClientOptions } from "../infra/client"
import type { ApiPath } from "../infra/types"
import type { ApiPath, ApiResponse } from "../infra/types"
export const ESTIMATE_ROUTES = {
INDEX: "/api/estimates",
@@ -25,8 +25,8 @@ export class EstimatesClient extends CrudClient<
// Note: GET /api/estimates/{id} is not in the OpenAPI schema.
// This method uses a type cast and relies on the backend supporting the route.
async getById(id: string) {
const data = await this.get(ESTIMATE_ROUTES.INDEX, { query: { id } } as never)
return {...data, data: (data as any)?.data?.[0] ?? null }
const data = await this.get(ESTIMATE_ROUTES.BY_ID, { params: { id } })
return data;
}
// ── Estimate Services ──
@@ -48,7 +48,7 @@ export class EstimatesClient extends CrudClient<
// ── Estimate Parts ──
async listParts(estimateId: string) {
return this.get(ESTIMATE_ROUTES.PARTS, { params: { id: estimateId } } as never)
return this.get(ESTIMATE_ROUTES.PARTS, { params: { id: estimateId } }) as Promise<ApiResponse<typeof ESTIMATE_ROUTES.PARTS, "get">>
}
async addPart(estimateId: string, payload: { part_id?: number; quantity?: number; rate?: string; description?: string }) {
+49 -6
View File
@@ -8,6 +8,7 @@ import type {
} from "./types"
import createClient from "openapi-fetch"
import type { paths } from "../../types/index"
import { logger } from "./logger"
type HttpMethod = "get" | "post" | "put" | "delete" | "patch"
@@ -73,6 +74,8 @@ export class ApiClient {
const opts = options as never
const body = (options as Record<string, unknown>).body as never
switch (method) {
case "get":
return this.get(ep, opts) as Promise<ApiResponse<Path, Method>>
@@ -96,12 +99,15 @@ export class ApiClient {
options: ApiRequestOptions<Path, "get"> = {} as ApiRequestOptions<Path, "get">,
): Promise<ApiResponse<Path, "get">> {
const requestOptions = this.toFetchOptions(options)
const startTime = Date.now()
logger.debug({ method: "GET", endpoint }, "API request")
try {
const { data, error, response } = await this.client.GET(endpoint, requestOptions as never)
return this.resolveResult(endpoint, "get", data, error, response)
return this.resolveResult(endpoint, "get", data, error, response, startTime)
} catch (err) {
if (err instanceof ApiError) throw err
logger.error({ method: "GET", endpoint, duration: Date.now() - startTime }, "Network error")
throw this.createNetworkError(endpoint, "get")
}
}
@@ -112,12 +118,15 @@ export class ApiClient {
options: Omit<ApiRequestOptions<Path, "post">, "body"> = {} as Omit<ApiRequestOptions<Path, "post">, "body">,
): Promise<ApiResponse<Path, "post">> {
const requestOptions = this.toFetchOptions({ ...options, body })
const startTime = Date.now()
logger.debug({ method: "POST", endpoint }, "API request")
try {
const { data, error, response } = await this.client.POST(endpoint, requestOptions as never)
return this.resolveResult(endpoint, "post", data, error, response)
return this.resolveResult(endpoint, "post", data, error, response, startTime)
} catch (err) {
if (err instanceof ApiError) throw err
logger.error({ method: "POST", endpoint, duration: Date.now() - startTime }, "Network error")
throw this.createNetworkError(endpoint, "post")
}
}
@@ -128,12 +137,15 @@ export class ApiClient {
options: Omit<ApiRequestOptions<Path, "put">, "body"> = {} as Omit<ApiRequestOptions<Path, "put">, "body">,
): Promise<ApiResponse<Path, "put">> {
const requestOptions = this.toFetchOptions({ ...options, body })
const startTime = Date.now()
logger.debug({ method: "PUT", endpoint }, "API request")
try {
const { data, error, response } = await this.client.PUT(endpoint, requestOptions as never)
return this.resolveResult(endpoint, "put", data, error, response)
return this.resolveResult(endpoint, "put", data, error, response, startTime)
} catch (err) {
if (err instanceof ApiError) throw err
logger.error({ method: "PUT", endpoint, duration: Date.now() - startTime }, "Network error")
throw this.createNetworkError(endpoint, "put")
}
}
@@ -143,12 +155,15 @@ export class ApiClient {
options: ApiRequestOptions<Path, "delete"> = {} as ApiRequestOptions<Path, "delete">,
): Promise<ApiResponse<Path, "delete">> {
const requestOptions = this.toFetchOptions(options)
const startTime = Date.now()
logger.debug({ method: "DELETE", endpoint }, "API request")
try {
const { data, error, response } = await this.client.DELETE(endpoint, requestOptions as never)
return this.resolveResult(endpoint, "delete", data, error, response)
return this.resolveResult(endpoint, "delete", data, error, response, startTime)
} catch (err) {
if (err instanceof ApiError) throw err
logger.error({ method: "DELETE", endpoint, duration: Date.now() - startTime }, "Network error")
throw this.createNetworkError(endpoint, "delete")
}
}
@@ -159,12 +174,15 @@ export class ApiClient {
options: Omit<ApiRequestOptions<Path, "patch">, "body"> = {} as Omit<ApiRequestOptions<Path, "patch">, "body">,
): Promise<ApiResponse<Path, "patch">> {
const requestOptions = this.toFetchOptions({ ...options, body })
const startTime = Date.now()
logger.debug({ method: "PATCH", endpoint }, "API request")
try {
const { data, error, response } = await this.client.PATCH(endpoint, requestOptions as never)
return this.resolveResult(endpoint, "patch", data, error, response)
return this.resolveResult(endpoint, "patch", data, error, response, startTime)
} catch (err) {
if (err instanceof ApiError) throw err
logger.error({ method: "PATCH", endpoint, duration: Date.now() - startTime }, "Network error")
throw this.createNetworkError(endpoint, "patch")
}
}
@@ -179,14 +197,21 @@ export class ApiClient {
headers.set("Accept", "application/json")
// Content-Type is intentionally omitted — fetch sets multipart/form-data + boundary automatically
const startTime = Date.now()
logger.debug({ method: "POST", endpoint }, "API request (form-data)")
const response = await fetch(url, { method: "POST", headers, body: formData })
const text = await response.text()
const data = text ? JSON.parse(text) : null
const duration = Date.now() - startTime
if (!response.ok) {
const level = response.status >= 500 ? "error" : "warn"
logger[level]({ method: "POST", endpoint, status: response.status, duration }, data?.message ?? "API request failed")
throw new ApiError(response.status, response.statusText, endpoint, "post", data)
}
logger.debug({ method: "POST", endpoint, status: response.status, duration }, "API request completed (form-data)")
return data
}
@@ -201,14 +226,21 @@ export class ApiClient {
init.body = JSON.stringify(options.body)
}
const startTime = Date.now()
logger.debug({ method, endpoint }, "API request (blob)")
const response = await fetch(url, init)
const duration = Date.now() - startTime
if (!response.ok) {
const text = await response.text()
const data = text ? JSON.parse(text) : null
const level = response.status >= 500 ? "error" : "warn"
logger[level]({ method, endpoint, status: response.status, duration }, data?.message ?? "API request failed")
throw new ApiError(response.status, response.statusText, endpoint, method.toLowerCase(), data)
}
logger.debug({ method, endpoint, status: response.status, duration }, "API request completed (blob)")
return response.blob()
}
@@ -250,17 +282,28 @@ export class ApiClient {
data: unknown,
error: unknown,
response: Response,
startTime: number,
): ApiResponse<Path, Method> {
const duration = Date.now() - startTime
if (error !== undefined) {
const payload = this.normalizeErrorPayload(error)
if (response.status >= 500) {
logger.error({ method: method.toUpperCase(), endpoint, status: response.status, duration }, payload?.message ?? "API request failed")
} else {
logger.warn({ method: method.toUpperCase(), endpoint, status: response.status, duration }, payload?.message ?? "API request failed")
}
throw new ApiError(
response.status,
response.statusText,
endpoint,
method,
this.normalizeErrorPayload(error),
payload,
)
}
logger.debug({ method: method.toUpperCase(), endpoint, status: response.status, duration, data }, "API request completed")
return data as ApiResponse<Path, Method>
}
+32
View File
@@ -0,0 +1,32 @@
import pino from "pino"
/**
* Isomorphic logger for the API client.
*
* - In Node.js (server / Next.js RSC / server actions): pino writes newline-delimited
* JSON to stdout — structured and machine-parseable.
* - In the browser (Next.js client components): pino switches to the browser
* transport automatically and delegates to the appropriate `console.*` method
* (console.debug, console.warn, console.error, …).
*
* Log level defaults:
* development → debug (all messages)
* production → warn (warnings + errors only)
*
* Override with the NEXT_PUBLIC_LOG_LEVEL env var (e.g. "info").
*/
const level =
(process.env.NEXT_PUBLIC_LOG_LEVEL as pino.Level | undefined) ??
(process.env.NODE_ENV === "production" ? "warn" : "debug")
export const logger = pino({
name: "garage-api",
level,
browser: {
/**
* Pass a plain object to `console.*` so DevTools display
* log fields (method, endpoint, status, duration) as expandable props.
*/
asObject: true,
},
})
+470 -19
View File
@@ -95,8 +95,8 @@ export interface paths {
};
requestBody?: never;
responses: {
/** @description OK */
200: {
/** @description Created */
201: {
headers: {
[name: string]: unknown;
};
@@ -14538,7 +14538,166 @@ export interface paths {
path?: never;
cookie?: never;
};
get?: never;
/** Display the specified estimate. */
get: {
parameters: {
query?: never;
header?: never;
path: {
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
/**
* @example {
* "data": {
* "id": 1,
* "title": "Estimate for Toyota Camry",
* "customer_id": 1,
* "vehicle_id": 1,
* "department_id": 1,
* "estimate_number": "EST-001",
* "date": "2026-03-31",
* "has_insurance": false,
* "enable_digital_authorisation": false,
* "insurance_type_id": 1,
* "insurer_id": 2,
* "service_writer_id": 1,
* "footer": "Thank you for your business.",
* "created_at": "2026-03-31T10:00:00.000000Z",
* "updated_at": "2026-03-31T10:00:00.000000Z",
* "labels": [
* {
* "id": 1,
* "title": "Urgent",
* "color_code": "#FF0000",
* "pivot": {
* "estimate_id": 1,
* "label_id": 1
* }
* }
* ],
* "customer_remarks": [
* {
* "id": 1,
* "estimate_id": 1,
* "remark": "Oil change recommended.",
* "created_at": "2026-03-31T10:00:00.000000Z",
* "updated_at": "2026-03-31T10:00:00.000000Z"
* }
* ],
* "customer": {
* "id": 1,
* "first_name": "John",
* "last_name": "Doe"
* },
* "vehicle": {
* "id": 1,
* "registration_number": "ABC-1234",
* "make": "Toyota",
* "model": "Camry"
* },
* "department": {
* "id": 1,
* "name": "Service"
* },
* "insurance_type": {
* "id": 1,
* "title": "Comprehensive"
* },
* "insurer": {
* "id": 2,
* "first_name": "Alex",
* "last_name": "Insurer"
* },
* "service_writer": {
* "id": 1,
* "first_name": "Sam",
* "last_name": "Writer"
* }
* }
* }
*/
"application/json": {
data?: {
id?: number;
title?: string;
customer_id?: number;
vehicle_id?: number;
department_id?: number;
estimate_number?: string;
date?: string;
has_insurance?: boolean;
enable_digital_authorisation?: boolean;
insurance_type_id?: number;
insurer_id?: number;
service_writer_id?: number;
footer?: string;
/** Format: date-time */
created_at?: string;
/** Format: date-time */
updated_at?: string;
labels?: {
id?: number;
title?: string;
color_code?: string;
pivot?: {
estimate_id?: number;
label_id?: number;
};
}[];
customer_remarks?: {
id?: number;
estimate_id?: number;
remark?: string;
/** Format: date-time */
created_at?: string;
/** Format: date-time */
updated_at?: string;
}[];
customer?: {
id?: number;
first_name?: string;
last_name?: string;
};
vehicle?: {
id?: number;
registration_number?: string;
make?: string;
model?: string;
};
department?: {
id?: number;
name?: string;
};
insurance_type?: {
id?: number;
title?: string;
};
insurer?: {
id?: number;
first_name?: string;
last_name?: string;
};
service_writer?: {
id?: number;
first_name?: string;
last_name?: string;
};
};
};
};
};
};
};
/** Update the specified estimate. */
put: {
parameters: {
@@ -29708,15 +29867,87 @@ export interface paths {
* "customer_id": 1,
* "vehicle_id": 1,
* "estimate_id": 1,
* "kms_in": 50000,
* "has_insurance": false,
* "insurer_id": 2,
* "invoice_to_id": 1,
* "billing_address_id": 10,
* "delivery_address_id": 11,
* "invoice_date": "2026-03-31",
* "due_date": "2026-04-14",
* "payment_terms_id": 1,
* "invoice_sequence_id": 1,
* "invoice_number": "INV-001",
* "invoice_title": "Tax Invoice",
* "department_id": 1,
* "notes": "string",
* "notes": "Vehicle service and parts",
* "terms_and_conditions": "Payment due in 14 days.",
* "status": "draft",
* "discount": "no"
* "received_payment": false,
* "payment_mode_id": 1,
* "deposit_to": "Main Account",
* "amount": 2500,
* "discount": "no",
* "inspection_categories": [
* {
* "inspection_category_id": 1,
* "rate_type": "flat_rate",
* "labor_rate": 500,
* "working_hours": 1,
* "labor_hours": 1,
* "rate": 500,
* "chart_of_account": "4000",
* "description": "General inspection",
* "department_id": 1
* }
* ],
* "parts": [
* {
* "part_id": 1,
* "quantity": 2,
* "rate": 150,
* "chart_of_account": "4100",
* "description": "Oil filter",
* "department_id": 1
* }
* ],
* "expenses": [
* {
* "expense_id": 1,
* "quantity": 1,
* "rate": 100,
* "chart_of_account": "4200",
* "description": "Shop supplies",
* "department_id": 1
* }
* ],
* "services": [
* {
* "service_id": 1,
* "rate_type": "hourly",
* "labor_rate_id": 1,
* "working_hours": 2,
* "labor_hours": 2,
* "quantity": 1,
* "rate": 800,
* "chart_of_account": "4300",
* "description": "Engine service",
* "department_id": 1
* }
* ],
* "service_groups": [
* {
* "service_group_id": 1,
* "rate_type": "flat_rate",
* "labor_rate_id": 1,
* "working_hours": 1,
* "labor_hours": 1,
* "rate": 600,
* "chart_of_account": "4400",
* "description": "Major service package",
* "department_id": 1
* }
* ]
* }
*/
"application/json": {
@@ -29724,40 +29955,102 @@ export interface paths {
customer_id?: number;
vehicle_id?: number;
estimate_id?: number;
kms_in?: number;
has_insurance?: boolean;
insurer_id?: number;
invoice_to_id?: number;
billing_address_id?: number;
delivery_address_id?: number;
invoice_date?: string;
due_date?: string;
payment_terms_id?: number;
invoice_sequence_id?: number;
invoice_number?: string;
invoice_title?: string;
department_id?: number;
notes?: string;
terms_and_conditions?: string;
status?: string;
received_payment?: boolean;
payment_mode_id?: number;
deposit_to?: string;
amount?: number;
discount?: string;
inspection_categories?: {
inspection_category_id?: number;
rate_type?: string;
labor_rate?: number;
working_hours?: number;
labor_hours?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
parts?: {
part_id?: number;
quantity?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
expenses?: {
expense_id?: number;
quantity?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
services?: {
service_id?: number;
rate_type?: string;
labor_rate_id?: number;
working_hours?: number;
labor_hours?: number;
quantity?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
service_groups?: {
service_group_id?: number;
rate_type?: string;
labor_rate_id?: number;
working_hours?: number;
labor_hours?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
};
};
};
responses: {
/** @description OK */
200: {
/** @description Created */
201: {
headers: {
[name: string]: unknown;
};
content: {
/**
* @example {
* "message": "Operation completed successfully.",
* "message": "Invoice created successfully.",
* "data": {
* "id": 1,
* "subject": "Invoice for Job Card 001",
* "subject": "Invoice for Service",
* "customer_id": 1,
* "vehicle_id": 1,
* "estimate_id": 1,
* "kms_in": 50000,
* "has_insurance": false,
* "insurer_id": 1,
* "insurer_id": 2,
* "invoice_to_id": 1,
* "billing_address_id": 1,
* "delivery_address_id": 1,
* "billing_address_id": 10,
* "delivery_address_id": 11,
* "invoice_date": "2026-03-31",
* "due_date": "2026-04-14",
* "payment_terms_id": 1,
@@ -29765,16 +30058,100 @@ export interface paths {
* "invoice_number": "INV-001",
* "invoice_title": "Tax Invoice",
* "department_id": 1,
* "notes": "string",
* "terms_and_conditions": "string",
* "notes": "Vehicle service and parts",
* "terms_and_conditions": "Payment due in 14 days.",
* "status": "draft",
* "received_payment": 0,
* "received_payment": false,
* "payment_mode_id": 1,
* "deposit_to": "string",
* "amount": 0,
* "deposit_to": "Main Account",
* "amount": 2500,
* "discount": "no",
* "created_at": "2026-03-31T10:00:00.000000Z",
* "updated_at": "2026-03-31T10:00:00.000000Z"
* "updated_at": "2026-03-31T10:00:00.000000Z",
* "customer": {
* "id": 1
* },
* "vehicle": {
* "id": 1
* },
* "invoice_sequence": {
* "id": 1,
* "title": "INV"
* },
* "department": {
* "id": 1,
* "name": "Service"
* },
* "invoice_inspection_categories": [
* {
* "id": 1,
* "invoice_id": 1,
* "inspection_category_id": 1,
* "rate_type": "flat_rate",
* "labor_rate": 500,
* "working_hours": 1,
* "labor_hours": 1,
* "rate": 500,
* "chart_of_account": "4000",
* "description": "General inspection",
* "department_id": 1
* }
* ],
* "invoice_parts": [
* {
* "id": 1,
* "invoice_id": 1,
* "part_id": 1,
* "quantity": 2,
* "rate": 150,
* "chart_of_account": "4100",
* "description": "Oil filter",
* "department_id": 1
* }
* ],
* "invoice_expenses": [
* {
* "id": 1,
* "invoice_id": 1,
* "expense_id": 1,
* "quantity": 1,
* "rate": 100,
* "chart_of_account": "4200",
* "description": "Shop supplies",
* "department_id": 1
* }
* ],
* "invoice_services": [
* {
* "id": 1,
* "invoice_id": 1,
* "service_id": 1,
* "rate_type": "hourly",
* "labor_rate_id": 1,
* "working_hours": 2,
* "labor_hours": 2,
* "quantity": 1,
* "rate": 800,
* "chart_of_account": "4300",
* "description": "Engine service",
* "department_id": 1
* }
* ],
* "invoice_service_groups": [
* {
* "id": 1,
* "invoice_id": 1,
* "service_group_id": 1,
* "rate_type": "flat_rate",
* "labor_rate_id": 1,
* "working_hours": 1,
* "labor_hours": 1,
* "rate": 600,
* "chart_of_account": "4400",
* "description": "Major service package",
* "department_id": 1
* }
* ]
* }
* }
*/
@@ -29802,7 +30179,7 @@ export interface paths {
notes?: string;
terms_and_conditions?: string;
status?: string;
received_payment?: number;
received_payment?: boolean;
payment_mode_id?: number;
deposit_to?: string;
amount?: number;
@@ -29811,6 +30188,80 @@ export interface paths {
created_at?: string;
/** Format: date-time */
updated_at?: string;
customer?: {
id?: number;
};
vehicle?: {
id?: number;
};
invoice_sequence?: {
id?: number;
title?: string;
};
department?: {
id?: number;
name?: string;
};
invoice_inspection_categories?: {
id?: number;
invoice_id?: number;
inspection_category_id?: number;
rate_type?: string;
labor_rate?: number;
working_hours?: number;
labor_hours?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
invoice_parts?: {
id?: number;
invoice_id?: number;
part_id?: number;
quantity?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
invoice_expenses?: {
id?: number;
invoice_id?: number;
expense_id?: number;
quantity?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
invoice_services?: {
id?: number;
invoice_id?: number;
service_id?: number;
rate_type?: string;
labor_rate_id?: number;
working_hours?: number;
labor_hours?: number;
quantity?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
invoice_service_groups?: {
id?: number;
invoice_id?: number;
service_group_id?: number;
rate_type?: string;
labor_rate_id?: number;
working_hours?: number;
labor_hours?: number;
rate?: number;
chart_of_account?: string;
description?: string;
department_id?: number;
}[];
};
};
};