fix invoice informations
This commit is contained in:
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}[];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user