Order Tax & Invoicing
The Orders module provides Indian GST-compliant tax calculation and sequential invoice generation with support for regular invoices, proforma invoices, and credit notes.
GST Calculation
The TaxService handles Indian GST rules:
- Intra-state (buyer and seller in same state): Tax splits into CGST + SGST (half rate each)
- Inter-state (different states): Full rate charged as IGST
Usage
use Modules\Orders\App\Services\TaxService;
$taxService = app(TaxService::class);
// Intra-state: Rs 1000 @ 18% GST
$result = $taxService->calculateTax(1000, null, true, 18);
// Returns:
// [
// 'rate' => 18.0,
// 'type' => 'gst',
// 'cgst_rate' => 9.0,
// 'sgst_rate' => 9.0,
// 'cgst' => 90.0,
// 'sgst' => 90.0,
// 'igst' => 0,
// 'total_tax' => 180.0,
// ]
// Inter-state: Rs 1000 @ 18% GST
$result = $taxService->calculateTax(1000, null, false, 18);
// Returns:
// [
// 'rate' => 18.0,
// 'type' => 'gst',
// 'cgst_rate' => 0, 'sgst_rate' => 0,
// 'cgst' => 0, 'sgst' => 0,
// 'igst_rate' => 18.0,
// 'igst' => 180.0,
// 'total_tax' => 180.0,
// ]
Method Signature
calculateTax(
float $amount, // Taxable amount
?string $hsnCode, // HSN code for rate lookup (optional)
bool $sameState = true, // true = CGST+SGST, false = IGST
?float $rateOverride // Override rate (skips HSN lookup)
): array
Tax Rate Lookup
Tax rates are resolved in order:
- If
$rateOverrideis provided, use it directly - If
$hsnCodeis provided, look up rate fromTaxConfigurationtable - If no match found, use the default GST configuration
- If no default exists, fall back to 18%
Supported GST Rates
Indian GST has standard rates: 0%, 5%, 12%, 18%, 28%. Configure via the TaxConfiguration model.
Tax Configuration Model
| Field | Type | Description |
|---|---|---|
id |
int | Primary key |
name |
string | Configuration name (e.g., "Standard GST 18%") |
rate |
decimal(5,2) | Tax rate percentage |
type |
string | gst, vat, sales_tax |
is_default |
boolean | Default configuration for this type |
hsn_codes |
jsonb | Array of HSN codes this rate applies to |
Example Configuration
TaxConfiguration::create([
'name' => 'GST 5% - Essential Items',
'rate' => 5.00,
'type' => 'gst',
'is_default' => false,
'hsn_codes' => ['0401', '0402', '1001', '1006'],
]);
TaxConfiguration::create([
'name' => 'GST 18% - Standard',
'rate' => 18.00,
'type' => 'gst',
'is_default' => true,
'hsn_codes' => [],
]);
TaxConfiguration::create([
'name' => 'GST 28% - Luxury Items',
'rate' => 28.00,
'type' => 'gst',
'is_default' => false,
'hsn_codes' => ['8703', '8711'],
]);
Invoice Generation
Invoice Model
| Field | Type | Description |
|---|---|---|
id |
UUID | Primary key |
order_id |
UUID | Parent order |
invoice_number |
string | Sequential number (e.g., INV-202603-0001) |
type |
string | invoice, credit_note, proforma |
status |
string | draft, issued, paid, cancelled |
subtotal |
decimal | Pre-tax amount |
tax_details |
jsonb | CGST/SGST/IGST breakdown |
total_tax |
decimal | Total tax amount |
discount |
decimal | Discount amount |
total |
decimal | Grand total |
billing_name |
string | Customer name |
billing_gstin |
string | Customer GSTIN |
billing_address |
jsonb | Billing address |
shipping_address |
jsonb | Shipping address |
line_items |
jsonb | Invoice line items |
pdf_path |
string | Generated PDF file path |
issued_at |
datetime | Issue date |
due_at |
datetime | Payment due date |
Creating an Invoice
POST /api/v1/orders/{order}/invoices
{
"type": "invoice"
}
The InvoiceService automatically:
- Loads order items, customer, and addresses
- Maps order items to invoice line items
- Calculates tax using
TaxService - Generates a sequential invoice number
- Sets due date to 30 days from issue
Response:
{
"data": {
"id": "uuid",
"invoice_number": "INV-202603-0001",
"type": "invoice",
"status": "issued",
"subtotal": 5000.00,
"tax_details": {
"rate": 18.0,
"type": "gst",
"cgst_rate": 9.0,
"sgst_rate": 9.0,
"cgst": 450.0,
"sgst": 450.0,
"igst": 0,
"total_tax": 900.0
},
"total_tax": 900.00,
"discount": 0.00,
"total": 5900.00,
"billing_name": "John Doe",
"line_items": [
{
"name": "Widget A",
"sku": "WA-001",
"quantity": 2,
"unit_price": 2500.00,
"tax": 450.00,
"discount": 0,
"total": 5000.00
}
],
"issued_at": "2026-03-08T10:00:00Z",
"due_at": "2026-04-07T10:00:00Z"
}
}
Invoice Number Format
| Type | Prefix | Format | Example |
|---|---|---|---|
| Invoice | INV |
INV-YYYYMM-NNNN |
INV-202603-0001 |
| Credit Note | CN |
CN-YYYYMM-NNNN |
CN-202603-0001 |
| Proforma | PI |
PI-YYYYMM-NNNN |
PI-202603-0001 |
Numbers are sequential within each prefix and month. The sequence resets each month.
Credit Notes
Issue a credit note for partial or full refunds:
use Modules\Orders\App\Services\InvoiceService;
$invoiceService = app(InvoiceService::class);
$creditNote = $invoiceService->generateCreditNote(
$order,
1500.00, // Amount
'Partial refund - defective item'
);
The credit note is created with:
- Type
credit_note CN-prefixed number- A single line item describing the reason
- Status
issued
Listing Invoices
GET /api/v1/orders/{order}/invoices
Returns all invoices and credit notes for an order.
GET /api/v1/invoices/{invoice}
Returns a single invoice with full details.
Integration with Returns
When a return is processed via ReturnService::processRefundForReturn(), you can generate a credit note alongside the refund:
$invoiceService->generateCreditNote(
$return->order,
$return->refund_amount,
"Return #{$return->return_number}: {$return->reason_category}"
);