lbyte-budget 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.simplecov +25 -0
- data/API_DOCUMENTATION.md +526 -0
- data/CHANGELOG.md +5 -0
- data/CLEANUP.md +85 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/INTEGRATION_GUIDE.md +452 -0
- data/LICENSE.txt +21 -0
- data/RAILS_USAGE.md +510 -0
- data/README.md +367 -0
- data/Rakefile +19 -0
- data/TESTING.md +243 -0
- data/TEST_IMPLEMENTATION_SUMMARY.md +246 -0
- data/TEST_SUITE.md +253 -0
- data/app/controllers/budget/application_controller.rb +10 -0
- data/app/controllers/budget/line_items_controller.rb +112 -0
- data/app/controllers/budget/payments_controller.rb +108 -0
- data/app/controllers/budget/quotes_controller.rb +180 -0
- data/app/models/budget/line_item.rb +59 -0
- data/app/models/budget/payment.rb +58 -0
- data/app/models/budget/quote.rb +158 -0
- data/app/views/budget/line_items/index.json.jbuilder +7 -0
- data/app/views/budget/line_items/show.json.jbuilder +6 -0
- data/app/views/budget/payments/index.json.jbuilder +6 -0
- data/app/views/budget/payments/show.json.jbuilder +5 -0
- data/app/views/budget/quotes/index.json.jbuilder +15 -0
- data/app/views/budget/quotes/show.json.jbuilder +23 -0
- data/config/routes.rb +12 -0
- data/db/migrate/20251129000001_create_budget_quotes.rb +17 -0
- data/db/migrate/20251129000002_create_budget_line_items.rb +17 -0
- data/db/migrate/20251129000003_create_budget_payments.rb +18 -0
- data/examples/basic_usage.rb +130 -0
- data/examples/test_examples.rb +113 -0
- data/lib/budget/engine.rb +25 -0
- data/lib/budget/line_item.rb +66 -0
- data/lib/budget/payment.rb +56 -0
- data/lib/budget/quote.rb +163 -0
- data/lib/budget/version.rb +5 -0
- data/lib/budget.rb +10 -0
- data/lib/generators/budget/INSTALL +46 -0
- data/lib/generators/budget/install_generator.rb +33 -0
- data/sig/budget.rbs +4 -0
- metadata +115 -0
data/RAILS_USAGE.md
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
# Rails Engine Installation & Usage Guide
|
|
2
|
+
|
|
3
|
+
## What is Budget?
|
|
4
|
+
|
|
5
|
+
Budget is a **Rails Engine** that provides complete quote/budget management functionality for businesses with advance payments and installment tracking.
|
|
6
|
+
|
|
7
|
+
**Features:**
|
|
8
|
+
- ✅ ActiveRecord models with associations
|
|
9
|
+
- ✅ Database migrations
|
|
10
|
+
- ✅ REST JSON API with JBuilder
|
|
11
|
+
- ✅ Business logic (calculations, validations)
|
|
12
|
+
- ✅ Complete Rails Engine integration
|
|
13
|
+
|
|
14
|
+
## Installation Steps
|
|
15
|
+
|
|
16
|
+
### 1. Add to Gemfile
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
gem 'budget-quotes'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Install the Gem
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bundle install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 3. Generate Migrations
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
rails generate budget:install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This creates three migration files in `db/migrate/`:
|
|
35
|
+
- `create_budget_quotes.rb`
|
|
36
|
+
- `create_budget_line_items.rb`
|
|
37
|
+
- `create_budget_payments.rb`
|
|
38
|
+
|
|
39
|
+
### 4. Run Migrations
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
rails db:migrate
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This creates three tables:
|
|
46
|
+
- `budget_quotes`
|
|
47
|
+
- `budget_line_items`
|
|
48
|
+
- `budget_payments`
|
|
49
|
+
|
|
50
|
+
## Database Tables Created
|
|
51
|
+
|
|
52
|
+
### budget_quotes
|
|
53
|
+
Stores customer quote information.
|
|
54
|
+
|
|
55
|
+
| Column | Type | Description |
|
|
56
|
+
|--------|------|-------------|
|
|
57
|
+
| id | integer | Primary key |
|
|
58
|
+
| customer_name | string | Customer name (required) |
|
|
59
|
+
| customer_contact | string | Phone/email |
|
|
60
|
+
| notes | text | Additional notes |
|
|
61
|
+
| quote_date | datetime | Quote creation date |
|
|
62
|
+
| created_at | datetime | Timestamp |
|
|
63
|
+
| updated_at | datetime | Timestamp |
|
|
64
|
+
|
|
65
|
+
### budget_line_items
|
|
66
|
+
Stores individual items in each quote.
|
|
67
|
+
|
|
68
|
+
| Column | Type | Description |
|
|
69
|
+
|--------|------|-------------|
|
|
70
|
+
| id | integer | Primary key |
|
|
71
|
+
| budget_quote_id | integer | Foreign key to quotes |
|
|
72
|
+
| description | string | Item description (required) |
|
|
73
|
+
| price | decimal(10,2) | Unit price (required) |
|
|
74
|
+
| category | string | lente, montura, tratamiento, other |
|
|
75
|
+
| quantity | integer | Quantity (default: 1) |
|
|
76
|
+
| created_at | datetime | Timestamp |
|
|
77
|
+
| updated_at | datetime | Timestamp |
|
|
78
|
+
|
|
79
|
+
### budget_payments
|
|
80
|
+
Stores payments made towards quotes.
|
|
81
|
+
|
|
82
|
+
| Column | Type | Description |
|
|
83
|
+
|--------|------|-------------|
|
|
84
|
+
| id | integer | Primary key |
|
|
85
|
+
| budget_quote_id | integer | Foreign key to quotes |
|
|
86
|
+
| amount | decimal(10,2) | Payment amount (required) |
|
|
87
|
+
| payment_date | datetime | When payment was made |
|
|
88
|
+
| payment_method | string | efectivo, tarjeta, transferencia, cheque, other |
|
|
89
|
+
| notes | text | Payment notes |
|
|
90
|
+
| created_at | datetime | Timestamp |
|
|
91
|
+
| updated_at | datetime | Timestamp |
|
|
92
|
+
|
|
93
|
+
## Usage Examples
|
|
94
|
+
|
|
95
|
+
### Creating a Quote
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
# In a controller or service
|
|
99
|
+
quote = Budget::Quote.create!(
|
|
100
|
+
customer_name: "María González",
|
|
101
|
+
customer_contact: "maria@example.com"
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Adding Line Items
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
# Add lenses
|
|
109
|
+
quote.add_line_item(
|
|
110
|
+
description: "Lentes progresivos alta gama",
|
|
111
|
+
price: 150.00,
|
|
112
|
+
category: "lente"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Add frame
|
|
116
|
+
quote.add_line_item(
|
|
117
|
+
description: "Montura titanio ligera",
|
|
118
|
+
price: 80.00,
|
|
119
|
+
category: "montura"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Add treatment (multiple quantity)
|
|
123
|
+
quote.line_items.create!(
|
|
124
|
+
description: "Protección UV",
|
|
125
|
+
price: 25.00,
|
|
126
|
+
category: "tratamiento",
|
|
127
|
+
quantity: 2
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Adding Payments
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
# Initial payment (adelanto)
|
|
135
|
+
quote.add_payment(
|
|
136
|
+
amount: 150.00,
|
|
137
|
+
payment_method: "efectivo",
|
|
138
|
+
notes: "Adelanto 50%"
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Later payment
|
|
142
|
+
quote.add_payment(
|
|
143
|
+
amount: 100.00,
|
|
144
|
+
payment_method: "tarjeta",
|
|
145
|
+
notes: "Pago parcial"
|
|
146
|
+
)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Querying Quotes
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
# Find quote by ID
|
|
153
|
+
quote = Budget::Quote.find(1)
|
|
154
|
+
|
|
155
|
+
# Recent quotes
|
|
156
|
+
recent = Budget::Quote.recent.limit(10)
|
|
157
|
+
|
|
158
|
+
# Find by customer name
|
|
159
|
+
quotes = Budget::Quote.by_customer("María")
|
|
160
|
+
|
|
161
|
+
# Pending quotes (not fully paid)
|
|
162
|
+
pending = Budget::Quote.pending
|
|
163
|
+
|
|
164
|
+
# With associations
|
|
165
|
+
quote = Budget::Quote.includes(:line_items, :payments).find(1)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Calculations
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
quote = Budget::Quote.find(1)
|
|
172
|
+
|
|
173
|
+
# Total price
|
|
174
|
+
quote.total # => 300.0
|
|
175
|
+
|
|
176
|
+
# Total paid
|
|
177
|
+
quote.total_paid # => 150.0
|
|
178
|
+
|
|
179
|
+
# Remaining balance
|
|
180
|
+
quote.remaining_balance # => 150.0
|
|
181
|
+
|
|
182
|
+
# Check if fully paid
|
|
183
|
+
quote.fully_paid? # => false
|
|
184
|
+
|
|
185
|
+
# Category breakdown
|
|
186
|
+
quote.category_breakdown
|
|
187
|
+
# => { lente: 150.0, montura: 80.0, tratamiento: 50.0, other: 20.0 }
|
|
188
|
+
|
|
189
|
+
# Initial payment
|
|
190
|
+
quote.initial_payment # => first Payment record
|
|
191
|
+
|
|
192
|
+
# Summary hash
|
|
193
|
+
quote.summary
|
|
194
|
+
# => { id: 1, customer_name: "María", total: 300.0, ... }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Formatting for Display
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
# Print formatted quote
|
|
201
|
+
puts quote
|
|
202
|
+
|
|
203
|
+
# Output:
|
|
204
|
+
# ============================================================
|
|
205
|
+
# PRESUPUESTO #1
|
|
206
|
+
# ============================================================
|
|
207
|
+
# Cliente: María González
|
|
208
|
+
# Contacto: maria@example.com
|
|
209
|
+
# Fecha: 29/11/2025
|
|
210
|
+
#
|
|
211
|
+
# DETALLE:
|
|
212
|
+
# ------------------------------------------------------------
|
|
213
|
+
# 1. Lente - Lentes progresivos: $150.00
|
|
214
|
+
# 2. Montura - Montura titanio: $80.00
|
|
215
|
+
# ...
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Controller Example
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
class QuotesController < ApplicationController
|
|
222
|
+
def create
|
|
223
|
+
@quote = Budget::Quote.create!(quote_params)
|
|
224
|
+
|
|
225
|
+
# Add items from form
|
|
226
|
+
params[:line_items].each do |item|
|
|
227
|
+
@quote.add_line_item(
|
|
228
|
+
description: item[:description],
|
|
229
|
+
price: item[:price],
|
|
230
|
+
category: item[:category]
|
|
231
|
+
)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
redirect_to quote_path(@quote), notice: "Quote created successfully"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def add_payment
|
|
238
|
+
@quote = Budget::Quote.find(params[:id])
|
|
239
|
+
@quote.add_payment(payment_params)
|
|
240
|
+
|
|
241
|
+
redirect_to quote_path(@quote), notice: "Payment added"
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
private
|
|
245
|
+
|
|
246
|
+
def quote_params
|
|
247
|
+
params.require(:quote).permit(:customer_name, :customer_contact, :notes)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def payment_params
|
|
251
|
+
params.require(:payment).permit(:amount, :payment_method, :notes)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## View Example (ERB)
|
|
257
|
+
|
|
258
|
+
```erb
|
|
259
|
+
<h1>Quote #<%= @quote.id %></h1>
|
|
260
|
+
|
|
261
|
+
<div class="customer-info">
|
|
262
|
+
<p><strong>Customer:</strong> <%= @quote.customer_name %></p>
|
|
263
|
+
<p><strong>Contact:</strong> <%= @quote.customer_contact %></p>
|
|
264
|
+
<p><strong>Date:</strong> <%= @quote.quote_date.strftime('%d/%m/%Y') %></p>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<h2>Line Items</h2>
|
|
268
|
+
<table>
|
|
269
|
+
<% @quote.line_items.each do |item| %>
|
|
270
|
+
<tr>
|
|
271
|
+
<td><%= item.category_name %></td>
|
|
272
|
+
<td><%= item.description %></td>
|
|
273
|
+
<td><%= number_to_currency(item.price) %></td>
|
|
274
|
+
<td><%= item.quantity %></td>
|
|
275
|
+
<td><%= number_to_currency(item.subtotal) %></td>
|
|
276
|
+
</tr>
|
|
277
|
+
<% end %>
|
|
278
|
+
</table>
|
|
279
|
+
|
|
280
|
+
<div class="totals">
|
|
281
|
+
<p><strong>Total:</strong> <%= number_to_currency(@quote.total) %></p>
|
|
282
|
+
<p><strong>Paid:</strong> <%= number_to_currency(@quote.total_paid) %></p>
|
|
283
|
+
<p><strong>Balance:</strong> <%= number_to_currency(@quote.remaining_balance) %></p>
|
|
284
|
+
<p><strong>Status:</strong>
|
|
285
|
+
<span class="<%= @quote.fully_paid? ? 'paid' : 'pending' %>">
|
|
286
|
+
<%= @quote.fully_paid? ? 'PAID' : 'PENDING' %>
|
|
287
|
+
</span>
|
|
288
|
+
</p>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
<h2>Payments</h2>
|
|
292
|
+
<ul>
|
|
293
|
+
<% @quote.payments.ordered.each do |payment| %>
|
|
294
|
+
<li><%= payment %></li>
|
|
295
|
+
<% end %>
|
|
296
|
+
</ul>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## API (JSON) Example
|
|
300
|
+
|
|
301
|
+
```ruby
|
|
302
|
+
# app/controllers/api/quotes_controller.rb
|
|
303
|
+
module Api
|
|
304
|
+
class QuotesController < ApplicationController
|
|
305
|
+
def show
|
|
306
|
+
@quote = Budget::Quote.includes(:line_items, :payments).find(params[:id])
|
|
307
|
+
|
|
308
|
+
render json: {
|
|
309
|
+
id: @quote.id,
|
|
310
|
+
customer_name: @quote.customer_name,
|
|
311
|
+
customer_contact: @quote.customer_contact,
|
|
312
|
+
quote_date: @quote.quote_date,
|
|
313
|
+
total: @quote.total,
|
|
314
|
+
total_paid: @quote.total_paid,
|
|
315
|
+
remaining_balance: @quote.remaining_balance,
|
|
316
|
+
fully_paid: @quote.fully_paid?,
|
|
317
|
+
line_items: @quote.line_items.map do |item|
|
|
318
|
+
{
|
|
319
|
+
description: item.description,
|
|
320
|
+
price: item.price,
|
|
321
|
+
category: item.category,
|
|
322
|
+
quantity: item.quantity,
|
|
323
|
+
subtotal: item.subtotal
|
|
324
|
+
}
|
|
325
|
+
end,
|
|
326
|
+
payments: @quote.payments.ordered.map do |payment|
|
|
327
|
+
{
|
|
328
|
+
amount: payment.amount,
|
|
329
|
+
payment_date: payment.payment_date,
|
|
330
|
+
payment_method: payment.payment_method_name,
|
|
331
|
+
notes: payment.notes
|
|
332
|
+
}
|
|
333
|
+
end
|
|
334
|
+
}
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Routes Example
|
|
341
|
+
|
|
342
|
+
```ruby
|
|
343
|
+
# config/routes.rb
|
|
344
|
+
Rails.application.routes.draw do
|
|
345
|
+
resources :quotes do
|
|
346
|
+
member do
|
|
347
|
+
post :add_payment
|
|
348
|
+
post :add_line_item
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
namespace :api do
|
|
353
|
+
resources :quotes, only: [:index, :show, :create]
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Validations
|
|
359
|
+
|
|
360
|
+
The models include built-in validations:
|
|
361
|
+
|
|
362
|
+
### Budget::Quote
|
|
363
|
+
- `customer_name` - required
|
|
364
|
+
- `quote_date` - automatically set if not provided
|
|
365
|
+
|
|
366
|
+
### Budget::LineItem
|
|
367
|
+
- `description` - required
|
|
368
|
+
- `price` - required, must be >= 0
|
|
369
|
+
- `quantity` - required, must be > 0
|
|
370
|
+
- `category` - must be in: lente, montura, tratamiento, other
|
|
371
|
+
|
|
372
|
+
### Budget::Payment
|
|
373
|
+
- `amount` - required, must be > 0
|
|
374
|
+
- `payment_date` - automatically set if not provided
|
|
375
|
+
- `payment_method` - must be in: efectivo, tarjeta, transferencia, cheque, other
|
|
376
|
+
|
|
377
|
+
## Scopes
|
|
378
|
+
|
|
379
|
+
### Budget::Quote
|
|
380
|
+
- `recent` - Orders by created_at DESC
|
|
381
|
+
- `by_customer(name)` - Search by customer name
|
|
382
|
+
- `pending` - Only quotes not fully paid
|
|
383
|
+
|
|
384
|
+
### Budget::Payment
|
|
385
|
+
- `ordered` - Orders by payment_date ASC
|
|
386
|
+
- `by_method(method)` - Filter by payment method
|
|
387
|
+
|
|
388
|
+
## Testing in Your Rails App
|
|
389
|
+
|
|
390
|
+
```ruby
|
|
391
|
+
# spec/models/budget/quote_spec.rb
|
|
392
|
+
require 'rails_helper'
|
|
393
|
+
|
|
394
|
+
RSpec.describe Budget::Quote, type: :model do
|
|
395
|
+
it "calculates total correctly" do
|
|
396
|
+
quote = create(:budget_quote)
|
|
397
|
+
quote.line_items.create!(description: "Test", price: 100, category: "other")
|
|
398
|
+
|
|
399
|
+
expect(quote.total).to eq(100)
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
it "tracks payments correctly" do
|
|
403
|
+
quote = create(:budget_quote)
|
|
404
|
+
quote.line_items.create!(description: "Test", price: 100, category: "other")
|
|
405
|
+
quote.payments.create!(amount: 50, payment_method: "efectivo")
|
|
406
|
+
|
|
407
|
+
expect(quote.remaining_balance).to eq(50)
|
|
408
|
+
expect(quote.fully_paid?).to be false
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Troubleshooting
|
|
414
|
+
|
|
415
|
+
### Migrations not found
|
|
416
|
+
If migrations aren't generated, ensure you've run:
|
|
417
|
+
```bash
|
|
418
|
+
rails generate budget:install
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Models not loading
|
|
422
|
+
Ensure Rails is properly loading the engine. Check that `config/application.rb` doesn't exclude engines.
|
|
423
|
+
|
|
424
|
+
### Foreign key errors
|
|
425
|
+
Ensure migrations were run in the correct order:
|
|
426
|
+
1. budget_quotes
|
|
427
|
+
2. budget_line_items
|
|
428
|
+
3. budget_payments
|
|
429
|
+
|
|
430
|
+
## JSON API Usage
|
|
431
|
+
|
|
432
|
+
The Budget Engine includes a complete REST JSON API. See **API_DOCUMENTATION.md** for full details.
|
|
433
|
+
|
|
434
|
+
### Mounting the Engine
|
|
435
|
+
|
|
436
|
+
In your Rails app's `config/routes.rb`:
|
|
437
|
+
|
|
438
|
+
```ruby
|
|
439
|
+
mount Budget::Engine => '/budget'
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
This makes all API endpoints available at `/budget/*`.
|
|
443
|
+
|
|
444
|
+
### Quick API Examples
|
|
445
|
+
|
|
446
|
+
#### Create a quote via API
|
|
447
|
+
```bash
|
|
448
|
+
curl -X POST http://localhost:3000/budget/quotes \
|
|
449
|
+
-H "Content-Type: application/json" \
|
|
450
|
+
-d '{"quote":{"customer_name":"María González","customer_contact":"555-1234"}}'
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
#### Add line item
|
|
454
|
+
```bash
|
|
455
|
+
curl -X POST http://localhost:3000/budget/quotes/1/line_items \
|
|
456
|
+
-H "Content-Type: application/json" \
|
|
457
|
+
-d '{"line_item":{"description":"Lentes","price":150.00,"category":"lente"}}'
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
#### Add payment
|
|
461
|
+
```bash
|
|
462
|
+
curl -X POST http://localhost:3000/budget/quotes/1/payments \
|
|
463
|
+
-H "Content-Type: application/json" \
|
|
464
|
+
-d '{"payment":{"amount":75.00,"payment_method":"efectivo"}}'
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### Get quote with calculations
|
|
468
|
+
```bash
|
|
469
|
+
curl http://localhost:3000/budget/quotes/1
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Response:
|
|
473
|
+
```json
|
|
474
|
+
{
|
|
475
|
+
"id": 1,
|
|
476
|
+
"customer_name": "María González",
|
|
477
|
+
"line_items": [...],
|
|
478
|
+
"payments": [...],
|
|
479
|
+
"totals": {
|
|
480
|
+
"total": 150.00,
|
|
481
|
+
"total_paid": 75.00,
|
|
482
|
+
"remaining_balance": 75.00,
|
|
483
|
+
"fully_paid": false
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Available Endpoints
|
|
489
|
+
|
|
490
|
+
- `GET /budget/quotes` - List all quotes
|
|
491
|
+
- `GET /budget/quotes/:id` - Get quote details
|
|
492
|
+
- `POST /budget/quotes` - Create quote
|
|
493
|
+
- `PATCH /budget/quotes/:id` - Update quote
|
|
494
|
+
- `DELETE /budget/quotes/:id` - Delete quote
|
|
495
|
+
- `GET /budget/quotes/:id/summary` - Get quote summary
|
|
496
|
+
- `GET /budget/quotes/:quote_id/line_items` - List line items
|
|
497
|
+
- `POST /budget/quotes/:quote_id/line_items` - Add line item
|
|
498
|
+
- `PATCH /budget/quotes/:quote_id/line_items/:id` - Update line item
|
|
499
|
+
- `DELETE /budget/quotes/:quote_id/line_items/:id` - Delete line item
|
|
500
|
+
- `GET /budget/quotes/:quote_id/payments` - List payments
|
|
501
|
+
- `POST /budget/quotes/:quote_id/payments` - Add payment
|
|
502
|
+
- `PATCH /budget/quotes/:quote_id/payments/:id` - Update payment
|
|
503
|
+
- `DELETE /budget/quotes/:quote_id/payments/:id` - Delete payment
|
|
504
|
+
|
|
505
|
+
See **API_DOCUMENTATION.md** for complete API reference with request/response examples.
|
|
506
|
+
|
|
507
|
+
## Support
|
|
508
|
+
|
|
509
|
+
For issues or questions, visit:
|
|
510
|
+
https://github.com/rubenpazch/lbyte-budget
|