You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: add architecture, sequence, ERD and resource diagrams to README
- Generic architecture flowchart right after the intro
- Runtime import sequence diagram
- Full ERD with every table and field
- Separate Eloquent models class diagram + list
- Separate Nova resources diagram + list (replaces the screenshot placeholder)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+302-4Lines changed: 302 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,6 +11,42 @@
11
11
12
12
You run one command. You get a fully populated `invoices` table with line items, tax details, seller and buyer parties, bank details, and the complete raw payload, all related and ready to query.
This package owns the blue boxes: the import command and job, the `InvoiceImporter`, the `InvoiceImported` event, and the optional Nova admin. The parsing itself is delegated to `sharpapi/laravel-invoice-parser`, which calls the SharpAPI endpoint. See [How an import flows](#how-an-import-flows) for the runtime sequence and [Data model](#data-model-all-tables-and-fields) for the full schema.
49
+
14
50
---
15
51
16
52
## Why this exists (the value)
@@ -192,9 +228,42 @@ public function handle(InvoiceImported $event): void
192
228
193
229
---
194
230
195
-
## Database schema overview
231
+
## How an import flows
232
+
233
+
```mermaid
234
+
sequenceDiagram
235
+
autonumber
236
+
participant App as Your app (command or job)
237
+
participant Parser as InvoiceParserService
238
+
participant API as SharpAPI
239
+
participant Importer as InvoiceImporter
240
+
participant DB as Database
241
+
participant Event as InvoiceImported
242
+
243
+
App->>Parser: parseInvoice(filePath)
244
+
Parser->>API: POST /finance/parse_invoice
245
+
API-->>Parser: status_url
246
+
App->>Parser: fetchResults(status_url)
247
+
Parser->>API: poll until job done
248
+
API-->>Parser: result JSON (array of invoices)
249
+
App->>Importer: storeMany(result, meta)
250
+
loop each invoice element
251
+
Importer->>DB: begin transaction
252
+
Importer->>DB: upsert invoice (idempotent on sharp_api_job_id)
253
+
Importer->>DB: insert parties, bank details, line items, tax details
254
+
Importer->>DB: commit
255
+
Importer-)Event: dispatch(InvoiceImported)
256
+
end
257
+
Importer-->>App: Collection of Invoice models
258
+
```
259
+
260
+
On import the mapper coerces empty strings to `null`, numeric strings to numbers, and date strings to Carbon dates. The whole element is also stored verbatim in `raw_payload` for lossless re-processing.
261
+
262
+
---
263
+
264
+
## Data model (all tables and fields)
196
265
197
-
All tables use the configurable `invoice_` prefix.
266
+
All tables use the configurable `invoice_` prefix (shown without the prefix below). Money columns are `decimal(15,2)`, dates are real `date` columns, and empty strings from the API are coerced to `null`.
198
267
199
268
| Table | Holds |
200
269
|-------|-------|
@@ -204,7 +273,212 @@ All tables use the configurable `invoice_` prefix.
204
273
|`invoice_line_items`| Every line item, with money and quantities as decimals and date fields as real dates. |
string sharp_api_job_id UK "nullable; idempotency key"
287
+
string source_file_path "nullable"
288
+
string source_file_name "nullable"
289
+
string document_type
290
+
string original_type_label
291
+
boolean is_invoice
292
+
boolean is_copy
293
+
string copy_type
294
+
string invoice_number "indexed"
295
+
date issue_date "indexed"
296
+
date due_date
297
+
date document_date
298
+
date order_date
299
+
date delivery_date
300
+
date shipping_date
301
+
date pricing_date
302
+
string currency "3 chars"
303
+
decimal exchange_rate "15,6"
304
+
string page_info
305
+
text amount_in_words
306
+
text notes
307
+
text remarks
308
+
text delivery_instructions
309
+
decimal late_payment_interest_rate "8,4"
310
+
json terms_and_conditions
311
+
decimal subtotal "15,2"
312
+
decimal gross_amount "15,2"
313
+
decimal total_discount_amount "15,2"
314
+
decimal shipping_charge "15,2"
315
+
decimal delivery_fee "15,2"
316
+
decimal total_excl_tax "15,2"
317
+
decimal total_tax_amount "15,2"
318
+
decimal service_tax_amount "15,2"
319
+
decimal total_incl_tax "15,2"
320
+
decimal rounding_adjustment "15,2"
321
+
decimal total_payable "15,2"
322
+
decimal amount_paid "15,2"
323
+
decimal amount_due "15,2"
324
+
json references
325
+
json e_invoice
326
+
json sales_info
327
+
json payment
328
+
json logistics
329
+
json source_pages
330
+
json raw_payload
331
+
timestamp created_at
332
+
timestamp updated_at
333
+
}
334
+
335
+
invoice_parties {
336
+
bigint id PK
337
+
bigint invoice_id FK
338
+
string role "seller or buyer"
339
+
string name
340
+
string trade_name
341
+
string registration_number
342
+
string tin
343
+
string brn
344
+
string sst_id
345
+
string gst_id
346
+
string vat_id
347
+
string msic_code
348
+
string business_activity
349
+
string customer_account_number
350
+
string billing_location_name
351
+
string billing_recipient_name
352
+
string billing_street_line_1
353
+
string billing_street_line_2
354
+
string billing_city
355
+
string billing_state
356
+
string billing_postcode
357
+
string billing_country
358
+
string delivery_recipient_name
359
+
string delivery_location_name
360
+
string delivery_street_line_1
361
+
string delivery_street_line_2
362
+
string delivery_city
363
+
string delivery_state
364
+
string delivery_postcode
365
+
string delivery_country
366
+
boolean delivery_address_same_as_billing
367
+
string phone
368
+
string fax
369
+
string email
370
+
string website
371
+
json contact_person
372
+
json attention_to
373
+
timestamp created_at
374
+
timestamp updated_at
375
+
}
376
+
377
+
invoice_bank_details {
378
+
bigint id PK
379
+
bigint invoice_party_id FK
380
+
string bank_name
381
+
string account_name
382
+
string account_number
383
+
string sort_code
384
+
string swift_code
385
+
string iban
386
+
timestamp created_at
387
+
timestamp updated_at
388
+
}
389
+
390
+
invoice_line_items {
391
+
bigint id PK
392
+
bigint invoice_id FK
393
+
integer line_number "indexed"
394
+
string item_code
395
+
string stock_code
396
+
string barcode
397
+
text description
398
+
string classification_code
399
+
string country_of_origin
400
+
decimal quantity "15,4"
401
+
decimal free_quantity "15,4"
402
+
string unit_of_measure
403
+
string unit_of_measure_raw
404
+
string pack_size
405
+
decimal total_units "15,4"
406
+
decimal weight "15,4"
407
+
string weight_uom
408
+
decimal unit_price "15,4"
409
+
decimal discount_percent "8,4"
410
+
decimal discount_amount "15,2"
411
+
decimal subtotal "15,2"
412
+
decimal tax_rate "8,4"
413
+
string tax_type
414
+
decimal tax_amount "15,2"
415
+
decimal total_excl_tax "15,2"
416
+
decimal total_incl_tax "15,2"
417
+
date expiry_date
418
+
string batch_lot_number
419
+
date service_start_date
420
+
date service_end_date
421
+
timestamp created_at
422
+
timestamp updated_at
423
+
}
424
+
425
+
invoice_tax_details {
426
+
bigint id PK
427
+
bigint invoice_id FK
428
+
string tax_type
429
+
decimal tax_rate "8,4"
430
+
decimal taxable_amount "15,2"
431
+
decimal tax_amount "15,2"
432
+
timestamp created_at
433
+
timestamp updated_at
434
+
}
435
+
```
436
+
437
+
---
438
+
439
+
## Eloquent models
440
+
441
+
The package ships five Eloquent models (namespace `SharpAPI\InvoiceManager\Models`). Each can be swapped for your own subclass via the `models.*` config keys.
@@ -251,7 +525,31 @@ If [Laravel Nova](https://nova.laravel.com/) is installed and `nova.enabled` is
251
525
252
526
If Nova is not installed, nothing happens and the rest of the package works exactly the same.
253
527
254
-
> Nova admin screenshot placeholder. Add a screenshot of the Invoice detail view here.
528
+
The package ships five Nova resources (namespace `SharpAPI\InvoiceManager\Nova`), listed separately from the Eloquent models above. Only the top-level **Invoice** resource appears in the navigation; the rest are exposed as related (HasMany) sub-resources from the invoice detail view.
|`Nova\InvoiceBankDetail`|`InvoiceBankDetail`| No (sub-resource) | Bank name, account name, account number, SWIFT, IBAN. |
551
+
552
+
To point the admin at your own customized resource, set `nova.resource` in the config to your subclass. The sub-resources are registered automatically alongside it.
0 commit comments