Pdf Changes Done

This commit is contained in:
Utkarsh Khedkar
2026-03-09 10:24:44 +05:30
parent c11467068c
commit 9cc6959396
32 changed files with 3416 additions and 2188 deletions

View File

@@ -8,6 +8,7 @@ use App\Models\InvoiceItem;
use App\Models\InvoiceInstallment;
use App\Models\InvoiceChargeGroup;
use App\Models\InvoiceChargeGroupItem;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
@@ -20,9 +21,9 @@ class AdminInvoiceController extends Controller
// -------------------------------------------------------------
public function index(Request $request)
{
// Container relation सह invoices load करतो
$query = Invoice::with(['items', 'customer', 'container']);
// Search
if ($request->filled('search')) {
$search = $request->search;
$query->where(function ($q) use ($search) {
@@ -30,42 +31,51 @@ class AdminInvoiceController extends Controller
->orWhere('customer_name', 'like', "%{$search}%");
});
}
// Status filter
if ($request->filled('status') && $request->status !== 'all') {
$query->where('status', $request->status);
}
// Date range filter (invoice_date वर)
if ($request->filled('start_date')) {
$query->whereDate('invoice_date', '>=', $request->start_date);
}
if ($request->filled('end_date')) {
$query->whereDate('invoice_date', '<=', $request->end_date);
}
// Latest first
$invoices = $query->latest()->get();
return view('admin.invoice', compact('invoices'));
}
}
// -------------------------------------------------------------
// POPUP VIEW (AJAX)
// POPUP VIEW + CUSTOMER DATA SYNC
// -------------------------------------------------------------
public function popup($id)
{
$invoice = Invoice::with([
'items',
'customer',
'container',
'chargeGroups.items.item',
'chargeGroups.items',
])->findOrFail($id);
// demo update असेल तर ठेव/काढ
$invoice->update([
'customer_email' => 'test@demo.com',
'customer_address' => 'TEST ADDRESS',
'pincode' => '999999',
]);
$shipment = null;
return view('admin.popup_invoice', compact('invoice', 'shipment'));
// आधीच group मध्ये असलेले item ids
$groupedItemIds = $invoice->chargeGroups
->flatMap(fn($group) => $group->items->pluck('invoice_item_id'))
->unique()
->values()
->toArray();
return view('admin.popup_invoice', compact('invoice', 'shipment', 'groupedItemIds'));
}
// -------------------------------------------------------------
@@ -134,10 +144,10 @@ class AdminInvoiceController extends Controller
$data['igst_percent'] = $taxPercent;
}
$gstAmount = ($finalAmount * $taxPercent) / 100;
$data['gst_amount'] = $gstAmount;
$gstAmount = ($finalAmount * $taxPercent) / 100;
$data['gst_amount'] = $gstAmount;
$data['final_amount_with_gst'] = $finalAmount + $gstAmount;
$data['gst_percent'] = $taxPercent;
$data['gst_percent'] = $taxPercent;
Log::info('📌 Final Calculated Invoice Values', [
'invoice_id' => $invoice->id,
@@ -177,7 +187,7 @@ class AdminInvoiceController extends Controller
}
// -------------------------------------------------------------
// 🔹 UPDATE INVOICE ITEMS (price + ttl_amount)
// UPDATE INVOICE ITEMS
// -------------------------------------------------------------
public function updateItems(Request $request, Invoice $invoice)
{
@@ -230,10 +240,16 @@ class AdminInvoiceController extends Controller
$gstAmount = $newBaseAmount * $gstPercent / 100;
$finalWithGst = $newBaseAmount + $gstAmount;
$invoice->final_amount = $newBaseAmount;
$invoice->gst_amount = $gstAmount;
$invoice->final_amount_with_gst = $finalWithGst;
$invoice->gst_percent = $gstPercent;
$invoice->final_amount = $newBaseAmount;
$invoice->gst_amount = $gstAmount;
$invoice->final_amount_with_gst = $finalWithGst;
$invoice->gst_percent = $gstPercent;
$invoice->save();
// ⭐ Total Charges (groups समावेत) पुन्हा कॅलक्युलेट
$chargeGroupsTotal = $invoice->chargeGroups()->sum('total_charge');
$invoice->charge_groups_total = $chargeGroupsTotal;
$invoice->grand_total_with_charges = $invoice->final_amount_with_gst + $chargeGroupsTotal;
$invoice->save();
Log::info('✅ Invoice items updated & totals recalculated', [
@@ -245,13 +261,15 @@ class AdminInvoiceController extends Controller
'cgst_percent' => $invoice->cgst_percent,
'sgst_percent' => $invoice->sgst_percent,
'igst_percent' => $invoice->igst_percent,
'charge_groups_total' => $invoice->charge_groups_total,
'grand_total_with_charges' => $invoice->grand_total_with_charges,
]);
return back()->with('success', 'Invoice items updated successfully.');
}
// -------------------------------------------------------------
// PDF GENERATION USING mPDF
// PDF GENERATION
// -------------------------------------------------------------
public function generateInvoicePDF($invoice)
{
@@ -302,7 +320,10 @@ class AdminInvoiceController extends Controller
$invoice = Invoice::findOrFail($invoice_id);
$paidTotal = $invoice->installments()->sum('amount');
$remaining = $invoice->final_amount_with_gst - $paidTotal;
// 👇 Total Charges (grand_total_with_charges) वरून remaining
$grandTotal = $invoice->grand_total_with_charges;
$remaining = $grandTotal - $paidTotal;
if ($request->amount > $remaining) {
return response()->json([
@@ -331,11 +352,12 @@ class AdminInvoiceController extends Controller
'installment' => $installment,
'totalPaid' => $newPaid,
'gstAmount' => $invoice->gst_amount,
'finalAmountWithGst' => $invoice->final_amount_with_gst,
'finalAmountWithGst' => $grandTotal, // इथे grand total पाठव
'baseAmount' => $invoice->final_amount,
'remaining' => max(0, $invoice->final_amount_with_gst - $newPaid),
'isCompleted' => $newPaid >= $invoice->final_amount_with_gst,
'remaining' => max(0, $grandTotal - $newPaid),
'isCompleted' => $newPaid >= $grandTotal,
]);
}
// -------------------------------------------------------------
@@ -348,34 +370,32 @@ class AdminInvoiceController extends Controller
$installment->delete();
$paidTotal = $invoice->installments()->sum('amount');
$remaining = $invoice->final_amount_with_gst - $paidTotal;
if ($remaining > 0 && $invoice->status === 'paid') {
$invoice->update(['status' => 'pending']);
}
$paidTotal = $invoice->installments()->sum('amount');
$grandTotal = $invoice->grand_total_with_charges;
$remaining = $grandTotal - $paidTotal;
return response()->json([
'status' => 'success',
'message' => 'Installment deleted.',
'totalPaid' => $paidTotal,
'gstAmount' => $invoice->gst_amount,
'finalAmountWithGst' => $invoice->final_amount_with_gst,
'finalAmountWithGst' => $grandTotal, // इथेही
'baseAmount' => $invoice->final_amount,
'remaining' => $remaining,
'isZero' => $paidTotal == 0,
]);
}
// -------------------------------------------------------------
// CHARGE GROUP SAVE (NEW)
// CHARGE GROUP SAVE (no AJAX branch)
// -------------------------------------------------------------
public function storeChargeGroup(Request $request, $invoiceId)
{
$invoice = Invoice::with('items')->findOrFail($invoiceId);
$data = $request->validate([
'group_name' => 'nullable|string|max:255',
'group_name' => 'required|string|max:255',
'basis_type' => 'required|in:ttl_qty,amount,ttl_cbm,ttl_kg',
'basis_value' => 'required|numeric',
'rate' => 'required|numeric|min:0.0001',
@@ -383,62 +403,47 @@ class AdminInvoiceController extends Controller
'item_ids' => 'required|array',
'item_ids.*' => 'integer|exists:invoice_items,id',
]);
$exists = InvoiceChargeGroup::where('invoice_id', $invoice->id)
->where('group_name', $data['group_name'])
->exists();
if ($exists) {
return back()
->withErrors(['group_name' => 'This group name is already used for this invoice.'])
->withInput();
}
$group = InvoiceChargeGroup::create([
'invoice_id' => $invoice->id,
'group_name' => $data['group_name'] ?? null,
'group_name' => $data['group_name'],
'basis_type' => $data['basis_type'],
'basis_value' => $data['basis_value'],
'rate' => $data['rate'],
'total_charge' => $data['auto_total'],
]);
foreach ($data['item_ids'] as $itemId) {
InvoiceChargeGroupItem::create([
'group_id' => $group->id,
'invoice_item_id' => $itemId,
]);
}
if ($request->ajax()) {
// load items with invoice item relation
$group->load(['items.item']);
// prepare simple array for JS
$itemsPayload = $group->items->map(function ($gi) {
$it = $gi->item;
return [
'description' => $it->description,
'qty' => $it->qty,
'ttlqty' => $it->ttl_qty,
'cbm' => $it->cbm,
'ttlcbm' => $it->ttl_cbm,
'kg' => $it->kg,
'ttlkg' => $it->ttl_kg,
'amount' => $it->ttl_amount,
];
});
return response()->json([
'success' => true,
'message' => 'Charge group created successfully.',
'group' => [
'id' => $group->id,
'group_name' => $group->group_name,
'basis_type' => $group->basis_type,
'basis_value' => $group->basis_value,
'rate' => $group->rate,
'total_charge'=> $group->total_charge,
'items' => $itemsPayload,
],
]);
}
// ⭐ Charge groups नुसार Total Charges सेट करा
$chargeGroupsTotal = $invoice->chargeGroups()->sum('total_charge');
$grandTotal = $invoice->final_amount_with_gst + $chargeGroupsTotal;
$invoice->update([
'charge_groups_total' => $chargeGroupsTotal,
'grand_total_with_charges' => $grandTotal,
]);
return redirect()
->back()
->with('success', 'Charge group saved successfully.');
}
public function download(Invoice $invoice)
{
if (!$invoice->pdf_path || !Storage::exists($invoice->pdf_path)) {

View File

@@ -70,11 +70,13 @@ class AdminOrderController extends Controller
'invoices.final_amount_with_gst',
'invoices.status as invoice_status',
'invoices.mark_no',
'invoices.container_id', // <<< हे नक्की घाल
'containers.container_number',
'containers.container_date',
DB::raw('COALESCE(invoices.company_name, mark_list.company_name) as company_name'),
DB::raw('COALESCE(invoices.customer_name, mark_list.customer_name) as customer_name')
)
->when($request->filled('search'), function ($q) use ($request) {
$search = trim($request->search);
$q->where(function ($qq) use ($search) {

View File

@@ -10,6 +10,8 @@ use App\Models\InvoiceItem;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
use Carbon\Carbon;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Facades\Storage; // <-- added for Excel download
class ContainerController extends Controller
{
@@ -241,8 +243,8 @@ class ContainerController extends Controller
}
// ROWS CLEANING
$dataRows = array_slice($rows, $headerRowIndex + 1);
$cleanedRows = [];
$dataRows = array_slice($rows, $headerRowIndex + 1);
$cleanedRows = [];
$unmatchedRowsData = [];
foreach ($dataRows as $offset => $row) {
@@ -253,7 +255,7 @@ class ContainerController extends Controller
$rowText = strtoupper(implode(' ', $trimmedRow));
if (
stripos($rowText, 'TOTAL') !== false ||
stripos($rowText, 'TTL') !== false ||
stripos($rowText, 'TTL') !== false ||
stripos($rowText, 'GRAND') !== false
) {
continue;
@@ -280,10 +282,7 @@ class ContainerController extends Controller
->withInput();
}
/*
* FORMULA CHECK UPDATED WITH AMOUNT FIX + NUMBER SANITIZER
*/
// FORMULA CHECK
$cleanNumber = function ($value) {
if (is_string($value)) {
$value = str_replace(',', '', trim($value));
@@ -311,7 +310,6 @@ class ContainerController extends Controller
$desc = $essentialColumns['desc_col'] !== null ? (string)($row[$essentialColumns['desc_col']] ?? '') : '';
$mark = $essentialColumns['itemno_col'] !== null ? (string)($row[$essentialColumns['itemno_col']] ?? '') : '';
// expected
$expTtlQty = $qty * $ctn;
$expTtlCbm = $cbm * $ctn;
$expTtlKg = $kg * $ctn;
@@ -350,7 +348,6 @@ class ContainerController extends Controller
}
if (!empty($rowErrors)) {
// full row data map for excel table
$rowData = [];
foreach ($header as $colIndex => $headingText) {
$value = $row[$colIndex] ?? null;
@@ -368,7 +365,7 @@ class ContainerController extends Controller
}
}
// MARK CHECK: strict - collect ALL marks + unmatched rows
// MARK CHECK
$marksFromExcel = [];
foreach ($cleanedRows as $item) {
$row = $item['row'];
@@ -397,7 +394,6 @@ class ContainerController extends Controller
$markErrors = [];
if (!empty($unmatchedMarks)) {
foreach ($cleanedRows as $item) {
$row = $item['row'];
$offset = $item['offset'];
@@ -523,17 +519,19 @@ class ContainerController extends Controller
$snap = $markToSnapshot[$firstMark] ?? null;
$invoice = new Invoice();
$invoice->container_id = $container->id;
$invoice->container_id = $container->id;
// $invoice->customer_id = $customerId;
// इथे Mark No सेट करतो
$invoice->mark_no = $firstMark;
$invoice->mark_no = $firstMark;
$invoice->invoice_number = $this->generateInvoiceNumber();
$invoice->invoice_date = now()->toDateString();
// NEW (add this):
$invoice->due_date = Carbon::parse($invoice->invoice_date)->addDays(10)->format('Y-m-d');
// invoice_date = container_date
$invoice->invoice_date = $container->container_date;
// due_date = container_date + 10 days
$invoice->due_date = Carbon::parse($invoice->invoice_date)
->addDays(10)
->format('Y-m-d');
if ($snap) {
$invoice->customer_name = $snap['customer_name'] ?? null;
@@ -550,8 +548,8 @@ class ContainerController extends Controller
$invoice->customer_address = null;
$invoice->pincode = null;
$uniqueMarks = array_unique(array_column($rowsForCustomer, 'mark'));
$invoice->notes = 'Auto-created from Container ' . $container->container_number
$uniqueMarks = array_unique(array_column($rowsForCustomer, 'mark'));
$invoice->notes = 'Auto-created from Container ' . $container->container_number
. ' for Mark(s): ' . implode(', ', $uniqueMarks);
$invoice->pdf_path = null;
$invoice->status = 'pending';
@@ -627,40 +625,120 @@ class ContainerController extends Controller
->where('id', $rowId)
->first();
if (!$row) continue;
if (!$row) {
continue;
}
// original update
// 1) update container_rows.data
$data = $row->data ?? [];
foreach ($cols as $colHeader => $value) {
$data[$colHeader] = $value;
}
$row->update([
'data' => $data,
]);
$row->update(['data' => $data]);
// 2) normalize keys
$normalizedMap = [];
foreach ($data as $key => $value) {
if ($key === null || $key === '') {
continue;
}
$normKey = strtoupper((string)$key);
$normKey = str_replace([' ', '/', '-', '.'], '', $normKey);
$normalizedMap[$normKey] = $value;
}
// helper: get first numeric value from given keys
$getFirstNumeric = function (array $map, array $possibleKeys) {
foreach ($possibleKeys as $search) {
$normSearch = strtoupper($search);
$normSearch = str_replace([' ', '/', '-', '.'], '', $normSearch);
foreach ($map as $nKey => $value) {
if (strpos($nKey, $normSearch) !== false) {
if (is_numeric($value)) {
return (float)$value;
}
if (is_string($value) && is_numeric(trim($value))) {
return (float)trim($value);
}
}
}
}
return 0;
};
// 3) read values QTY vs TTLQTY separately
$ctnKeys = ['CTN', 'CTNS'];
$qtyKeys = ['QTY', 'PCS', 'PIECES']; // per-carton qty
$ttlQtyKeys = ['ITLQTY', 'TOTALQTY', 'TTLQTY']; // total qty
$cbmKeys = ['TOTALCBM', 'TTLCBM', 'ITLCBM', 'CBM'];
$kgKeys = ['TOTALKG', 'TTKG', 'KG', 'WEIGHT'];
$amountKeys = ['AMOUNT', 'TTLAMOUNT', 'TOTALAMOUNT'];
$ctn = $getFirstNumeric($normalizedMap, $ctnKeys);
// per carton qty
$qty = $getFirstNumeric($normalizedMap, $qtyKeys);
// total qty direct from TOTALQTY/TTLQTY/ITLQTY
$ttlQ = $getFirstNumeric($normalizedMap, $ttlQtyKeys);
// if total column is 0 then compute ctn * qty
if ($ttlQ == 0 && $ctn && $qty) {
$ttlQ = $ctn * $qty;
}
$cbm = $getFirstNumeric($normalizedMap, ['CBM']);
$ttlC = $getFirstNumeric($normalizedMap, ['TOTALCBM', 'TTLCBM', 'ITLCBM']);
if ($ttlC == 0 && $cbm && $ctn) {
$ttlC = $cbm * $ctn;
}
$kg = $getFirstNumeric($normalizedMap, ['KG', 'WEIGHT']);
$ttlK = $getFirstNumeric($normalizedMap, ['TOTALKG', 'TTKG']);
if ($ttlK == 0 && $kg && $ctn) {
$ttlK = $kg * $ctn;
}
$price = $getFirstNumeric($normalizedMap, ['PRICE', 'RATE']);
$amount = $getFirstNumeric($normalizedMap, $amountKeys);
if ($amount == 0 && $price && $ttlQ) {
$amount = $price * $ttlQ;
}
// 4) get description
$desc = null;
foreach (['DESCRIPTION', 'DESC'] as $dKey) {
$normD = str_replace([' ', '/', '-', '.'], '', strtoupper($dKey));
foreach ($normalizedMap as $nKey => $v) {
if (strpos($nKey, $normD) !== false) {
$desc = is_string($v) ? trim($v) : $v;
break 2;
}
}
}
// extra: update linked invoice items & invoice totals
$rowIndex = $row->row_index;
$ctn = (float) ($data['CTN'] ?? $data['CTNS'] ?? 0);
$qty = (float) ($data['QTY'] ?? 0);
$ttlQ = (float) ($data['TTLQTY'] ?? $data['TOTALQTY'] ?? $data['TTL/QTY'] ?? ($ctn * $qty));
$price = (float) ($data['PRICE'] ?? 0);
$cbm = (float) ($data['CBM'] ?? 0);
$ttlC = (float) ($data['TOTALCBM'] ?? $data['TTL CBM'] ?? ($cbm * $ctn));
$kg = (float) ($data['KG'] ?? 0);
$ttlK = (float) ($data['TOTALKG'] ?? $data['TTL KG'] ?? ($kg * $ctn));
$amount = (float) ($data['AMOUNT'] ?? ($price * $ttlQ));
$desc = $data['DESCRIPTION'] ?? $data['DESC'] ?? null;
// 5) find linked invoice_items
$items = InvoiceItem::where('container_id', $container->id)
->where('container_row_index', $rowIndex)
->get();
if ($items->isEmpty() && $desc) {
$items = InvoiceItem::where('container_id', $container->id)
->whereNull('container_row_index')
->where('description', $desc)
->get();
}
// 6) update invoice_items + recalc invoice totals
foreach ($items as $item) {
$item->description = $desc;
$item->ctn = $ctn;
$item->qty = $qty;
$item->ttl_qty = $ttlQ;
$item->qty = $qty; // per carton
$item->ttl_qty = $ttlQ; // total
$item->price = $price;
$item->ttl_amount = $amount;
$item->cbm = $cbm;
@@ -703,33 +781,39 @@ class ContainerController extends Controller
->with('success', 'Excel rows updated successfully.');
}
// app/Http/Controllers/ContainerController.php
public function updateStatus(Request $request, Container $container)
{
$request->validate([
'status' => 'required|in:pending,in-progress,completed,cancelled',
]);
$container->status = $request->status;
$container->save();
// जर AJAX असेल तर JSON दे
if ($request->wantsJson() || $request->ajax()) {
return response()->json([
'success' => true,
'status' => $container->status,
public function updateStatus(Request $request, Container $container)
{
$request->validate([
'status' => 'required|in:container-ready,export-custom,international-transit,arrived-at-india,import-custom,warehouse,domestic-distribution,out-for-delivery,delivered',
]);
$container->status = $request->status;
$container->save();
if ($request->wantsJson() || $request->ajax()) {
return response()->json([
'success' => true,
'status' => $container->status,
]);
}
return back()->with('success', 'Container status updated.');
}
// normal form submit असेल तर redirect
return back()->with('success', 'Container status updated.');
}
public function destroy(Container $container)
{
$container->delete();
return redirect()->route('containers.index')->with('success', 'Container deleted.');
if (request()->wantsJson() || request()->ajax()) {
return response()->json([
'success' => true,
'message' => 'Container deleted',
]);
}
return redirect()
->route('containers.index')
->with('success', 'Container deleted.');
}
private function generateInvoiceNumber(): string
@@ -755,4 +839,105 @@ public function updateStatus(Request $request, Container $container)
return 'INV-' . $year . '-' . str_pad($nextSeq, 6, '0', STR_PAD_LEFT);
}
public function downloadPdf(Container $container)
{
$container->load('rows');
$pdf = Pdf::loadView('admin.container_pdf', [
'container' => $container,
])->setPaper('a4', 'landscape');
$fileName = 'container-'.$container->container_number.'.pdf';
return $pdf->download($fileName);
}
public function downloadExcel(Container $container)
{
if (!$container->excel_file) {
abort(404, 'Excel file not found on record.');
}
// Stored path like "containers/abc.xlsx"
$path = $container->excel_file;
if (!Storage::exists($path)) {
abort(404, 'Excel file missing on server.');
}
$fileName = 'container-'.$container->container_number.'.xlsx';
return Storage::download($path, $fileName);
}
public function popupPopup(Container $container)
{
// existing show सारखाच data वापरू
$container->load('rows');
// summary आधीपासून index() मध्ये जसा काढतोस तसाच logic reuse
$rows = $container->rows ?? collect();
$totalCtn = 0;
$totalQty = 0;
$totalCbm = 0;
$totalKg = 0;
$ctnKeys = ['CTN', 'CTNS'];
$qtyKeys = ['ITLQTY', 'TOTALQTY', 'TTLQTY', 'QTY', 'PCS', 'PIECES'];
$cbmKeys = ['TOTALCBM', 'TTLCBM', 'ITLCBM', 'CBM'];
$kgKeys = ['TOTALKG', 'TTKG', 'KG', 'WEIGHT'];
$getFirstNumeric = function (array $data, array $possibleKeys) {
$normalizedMap = [];
foreach ($data as $key => $value) {
if ($key === null) continue;
$normKey = strtoupper((string)$key);
$normKey = str_replace([' ', ',', '-', '.', "\n", "\r", "\t"], '', $normKey);
$normalizedMap[$normKey] = $value;
}
foreach ($possibleKeys as $search) {
$normSearch = strtoupper($search);
$normSearch = str_replace([' ', ',', '-', '.', "\n", "\r", "\t"], '', $normSearch);
foreach ($normalizedMap as $nKey => $value) {
if (strpos($nKey, $normSearch) !== false) {
if (is_numeric($value)) {
return (float)$value;
}
if (is_string($value) && is_numeric(trim($value))) {
return (float)trim($value);
}
}
}
}
return 0;
};
foreach ($rows as $row) {
$data = $row->data ?? [];
if (!is_array($data)) continue;
$totalCtn += $getFirstNumeric($data, $ctnKeys);
$totalQty += $getFirstNumeric($data, $qtyKeys);
$totalCbm += $getFirstNumeric($data, $cbmKeys);
$totalKg += $getFirstNumeric($data, $kgKeys);
}
$summary = [
'total_ctn' => round($totalCtn, 2),
'total_qty' => round($totalQty, 2),
'total_cbm' => round($totalCbm, 3),
'total_kg' => round($totalKg, 2),
];
return view('admin.partials.container_popup_readonly', [
'container' => $container,
'summary' => $summary,
]);
}
}

View File

@@ -11,6 +11,8 @@ class InvoiceItem extends Model
protected $fillable = [
'invoice_id',
'container_id', // Container mapping
'container_row_index', // Container row index
'description',
'ctn',
@@ -38,7 +40,6 @@ class InvoiceItem extends Model
return $this->belongsTo(Invoice::class);
}
public function chargeGroupItems()
{
return $this->hasMany(InvoiceChargeGroupItem::class, 'invoice_item_id');
@@ -114,4 +115,3 @@ class InvoiceItem extends Model
return $basis * $rate;
}
}

View File

@@ -89,10 +89,11 @@ class User extends Authenticatable implements JWTSubject
{
return [];
}
public function invoices()
{
return $this->hasMany(\App\Models\Invoice::class, 'customer_id', 'id');
}
public function invoices()
{
return $this->hasMany(\App\Models\Invoice::class, 'customer_id', 'customer_id');
}
// App\Models\User.php