Merge pull request #66 from denisdulici/accrual

Accrued invoices/bills
This commit is contained in:
Denis Duliçi 2017-11-07 05:15:19 +03:00 committed by GitHub
commit 96f98e77d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 562 additions and 387 deletions

View File

@ -18,6 +18,8 @@ class Dashboard extends Controller
{ {
use Currencies; use Currencies;
public $today;
/** /**
* Display a listing of the resource. * Display a listing of the resource.
* *
@ -25,8 +27,8 @@ class Dashboard extends Controller
*/ */
public function index() public function index()
{ {
$td = Date::today(); $this->today = Date::today();
$month_days = $td->daysInMonth; $month_days = $this->today->daysInMonth;
/* /*
* Cash Flow * Cash Flow
@ -78,53 +80,16 @@ class Dashboard extends Controller
$incomes = $expenses = array(); $incomes = $expenses = array();
$incomes_amount = $expenses_amount = 0; $incomes_amount = $expenses_amount = 0;
$open_invoice = $overdue_invoice = 0;
$open_bill = $overdue_bill = 0;
$invoice_paid_amount = $bill_paid_amount = 0;
$today = $td->toDateString();
// Invoices // Invoices
$invoices = Invoice::with('payments')->get(); $invoices = Invoice::with('payments')->accrued()->get();
list($invoice_paid_amount, $open_invoice, $overdue_invoice) = $this->getTotals($invoices, 'invoice');
foreach ($invoices as $invoice) {
$invoice_payments = 0;
foreach ($invoice->payments as $payment) {
$invoice_payments += $payment->getConvertedAmount();
}
$invoice_paid_amount += $invoice_payments;
// Check if it's open or overdue invoice
if ($invoice->due_at > $today) {
$open_invoice += $invoice->getConvertedAmount() - $invoice_payments;
} else {
$overdue_invoice += $invoice->getConvertedAmount() - $invoice_payments;
}
}
$incomes_amount += $invoice_paid_amount; $incomes_amount += $invoice_paid_amount;
// Bills // Bills
$bills = Bill::with('payments')->get(); $bills = Bill::with('payments')->accrued()->get();
list($bill_paid_amount, $open_bill, $overdue_bill) = $this->getTotals($bills, 'bill');
foreach ($bills as $bill) {
$bill_payments = 0;
foreach ($bill->payments as $payment) {
$bill_payments += $payment->getConvertedAmount();
}
$bill_paid_amount += $bill_payments;
// Check if it's open or overdue bill
if ($bill->due_at > $today) {
$open_bill += $bill->getConvertedAmount() - $bill_payments;
} else {
$overdue_bill += $bill->getConvertedAmount() - $bill_payments;
}
}
$expenses_amount += $bill_paid_amount; $expenses_amount += $bill_paid_amount;
@ -286,15 +251,15 @@ class Dashboard extends Controller
* Latest Incomes * Latest Incomes
*/ */
$latest_incomes = collect(InvoicePayment::latest()->take(5)->get()); $latest_incomes = collect(Invoice::accrued()->latest()->take(10)->get());
$latest_incomes = $latest_incomes->merge(Revenue::latest()->take(5)->get())->sortByDesc('paid_at'); $latest_incomes = $latest_incomes->merge(Revenue::latest()->take(10)->get())->take(5)->sortByDesc('invoiced_at');
/* /*
* Latest Expenses * Latest Expenses
*/ */
$latest_expenses = collect(BillPayment::latest()->take(5)->get()); $latest_expenses = collect(Bill::accrued()->latest()->take(10)->get());
$latest_expenses = $latest_expenses->merge(Payment::latest()->take(5)->get())->sortByDesc('paid_at'); $latest_expenses = $latest_expenses->merge(Payment::latest()->take(10)->get())->take(5)->sortByDesc('billed_at');
return view('dashboard.dashboard.index', compact( return view('dashboard.dashboard.index', compact(
'total_incomes', 'total_incomes',
@ -364,16 +329,16 @@ class Dashboard extends Controller
$items_1 = $m1::whereBetween('paid_at', [$sub, $now])->get(); $items_1 = $m1::whereBetween('paid_at', [$sub, $now])->get();
$this->setTotals($totals, $items_1, $date_format); $this->setCashFlowTotals($totals, $items_1, $date_format);
$items_2 = $m2::whereBetween('paid_at', [$sub, $now])->get(); $items_2 = $m2::whereBetween('paid_at', [$sub, $now])->get();
$this->setTotals($totals, $items_2, $date_format); $this->setCashFlowTotals($totals, $items_2, $date_format);
return $totals; return $totals;
} }
private function setTotals(&$totals, $items, $date_format) private function setCashFlowTotals(&$totals, $items, $date_format)
{ {
foreach ($items as $item) { foreach ($items as $item) {
$i = Date::parse($item->paid_at)->format($date_format); $i = Date::parse($item->paid_at)->format($date_format);
@ -382,6 +347,39 @@ class Dashboard extends Controller
} }
} }
private function getTotals($items, $type)
{
$paid = $open = $overdue = 0;
$today = $this->today->toDateString();
foreach ($items as $item) {
$paid += $item->getConvertedAmount();
$code_field = $type . '_status_code';
if ($item->$code_field == 'paid') {
continue;
}
$payments = 0;
if ($item->$code_field == 'partial') {
foreach ($item->payments as $payment) {
$payments += $payment->getConvertedAmount();
}
}
// Check if it's open or overdue invoice
if ($item->due_at > $today) {
$open += $item->getConvertedAmount() - $payments;
} else {
$overdue += $item->getConvertedAmount() - $payments;
}
}
return array($paid, $open, $overdue);
}
private function getProfit($incomes, $expenses) private function getProfit($incomes, $expenses)
{ {
$profit = []; $profit = [];

View File

@ -41,10 +41,10 @@ class Bills extends Controller
$vendors = collect(Vendor::enabled()->pluck('name', 'id')) $vendors = collect(Vendor::enabled()->pluck('name', 'id'))
->prepend(trans('general.all_type', ['type' => trans_choice('general.vendors', 2)]), ''); ->prepend(trans('general.all_type', ['type' => trans_choice('general.vendors', 2)]), '');
$status = collect(BillStatus::all()->pluck('name', 'code')) $statuses = collect(BillStatus::all()->pluck('name', 'code'))
->prepend(trans('general.all_type', ['type' => trans_choice('general.statuses', 2)]), ''); ->prepend(trans('general.all_type', ['type' => trans_choice('general.statuses', 2)]), '');
return view('expenses.bills.index', compact('bills', 'vendors', 'status')); return view('expenses.bills.index', compact('bills', 'vendors', 'statuses'));
} }
/** /**
@ -81,133 +81,6 @@ class Bills extends Controller
return view('expenses.bills.show', compact('bill', 'accounts', 'currencies', 'account_currency_code', 'vendors', 'categories', 'payment_methods')); return view('expenses.bills.show', compact('bill', 'accounts', 'currencies', 'account_currency_code', 'vendors', 'categories', 'payment_methods'));
} }
/**
* Show the form for viewing the specified resource.
*
* @param int $bill_id
*
* @return Response
*/
public function printBill($bill_id)
{
$paid = 0;
$bill = Bill::where('id', $bill_id)->first();
foreach ($bill->payments as $item) {
$item->default_currency_code = $bill->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$bill->paid = $paid;
return view('expenses.bills.bill', compact('bill'));
}
/**
* Show the form for viewing the specified resource.
*
* @param int $bill_id
*
* @return Response
*/
public function pdfBill($bill_id)
{
$paid = 0;
$bill = Bill::where('id', $bill_id)->first();
foreach ($bill->payments as $item) {
$item->default_currency_code = $bill->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$bill->paid = $paid;
$html = view('expenses.bills.bill', compact('bill'))->render();
$pdf = \App::make('dompdf.wrapper');
$pdf->loadHTML($html);
$file_name = 'bill_'.time().'.pdf';
return $pdf->download($file_name);
}
/**
* Show the form for viewing the specified resource.
*
* @param PaymentRequest $request
*
* @return Response
*/
public function payment(PaymentRequest $request)
{
// Get currency object
$currency = Currency::where('code', $request['currency_code'])->first();
$request['currency_code'] = $currency->code;
$request['currency_rate'] = $currency->rate;
// Upload attachment
$attachment_path = $this->getUploadedFilePath($request->file('attachment'), 'revenues');
if ($attachment_path) {
$request['attachment'] = $attachment_path;
}
$bill = Bill::find($request['bill_id']);
if ($request['currency_code'] == $bill->currency_code) {
if ($request['amount'] > $bill->amount) {
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
return response()->json($message);
} elseif ($request['amount'] == $bill->amount) {
$bill->bill_status_code = 'paid';
} else {
$bill->bill_status_code = 'partial';
}
} else {
$request_bill = new Bill();
$request_bill->amount = (float) $request['amount'];
$request_bill->currency_code = $currency->code;
$request_bill->currency_rate = $currency->rate;
$amount = $request_bill->getConvertedAmount();
if ($amount > $bill->amount) {
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
return response()->json($message);
} elseif ($amount == $bill->amount) {
$bill->bill_status_code = 'paid';
} else {
$bill->bill_status_code = 'partial';
}
}
$bill->save();
$bill_payment = BillPayment::create($request->input());
$request['status_code'] = $bill->bill_status_code;
$request['notify'] = 0;
$desc_date = Date::parse($request['paid_at'])->format($this->getCompanyDateFormat());
$desc_amount = money((float) $request['amount'], $request['currency_code'], true)->format();
$request['description'] = $desc_date . ' ' . $desc_amount;
BillHistory::create($request->input());
$message = trans('messages.success.added', ['type' => trans_choice('general.revenues', 1)]);
return response()->json($message);
}
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
* *
@ -250,7 +123,7 @@ class Bills extends Controller
$request['currency_code'] = $currency->code; $request['currency_code'] = $currency->code;
$request['currency_rate'] = $currency->rate; $request['currency_rate'] = $currency->rate;
$request['bill_status_code'] = 'new'; $request['bill_status_code'] = 'draft';
$request['amount'] = 0; $request['amount'] = 0;
@ -429,8 +302,6 @@ class Bills extends Controller
$request['currency_code'] = $currency->code; $request['currency_code'] = $currency->code;
$request['currency_rate'] = $currency->rate; $request['currency_rate'] = $currency->rate;
$request['bill_status_code'] = 'updated';
$request['amount'] = 0; $request['amount'] = 0;
// Upload attachment // Upload attachment
@ -587,6 +458,151 @@ class Bills extends Controller
return redirect('expenses/bills'); return redirect('expenses/bills');
} }
/**
* Mark the invoice as sent.
*
* @param int $invoice_id
*
* @return Response
*/
public function markReceived($bill_id)
{
$bill = Bill::find($bill_id);
$bill->bill_status_code = 'received';
$bill->save();
flash(trans('bills.marked_received'))->success();
return redirect()->back();
}
/**
* Show the form for viewing the specified resource.
*
* @param int $bill_id
*
* @return Response
*/
public function printBill($bill_id)
{
$paid = 0;
$bill = Bill::where('id', $bill_id)->first();
foreach ($bill->payments as $item) {
$item->default_currency_code = $bill->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$bill->paid = $paid;
return view('expenses.bills.bill', compact('bill'));
}
/**
* Show the form for viewing the specified resource.
*
* @param int $bill_id
*
* @return Response
*/
public function pdfBill($bill_id)
{
$paid = 0;
$bill = Bill::where('id', $bill_id)->first();
foreach ($bill->payments as $item) {
$item->default_currency_code = $bill->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$bill->paid = $paid;
$html = view('expenses.bills.bill', compact('bill'))->render();
$pdf = \App::make('dompdf.wrapper');
$pdf->loadHTML($html);
$file_name = 'bill_'.time().'.pdf';
return $pdf->download($file_name);
}
/**
* Show the form for viewing the specified resource.
*
* @param PaymentRequest $request
*
* @return Response
*/
public function payment(PaymentRequest $request)
{
// Get currency object
$currency = Currency::where('code', $request['currency_code'])->first();
$request['currency_code'] = $currency->code;
$request['currency_rate'] = $currency->rate;
// Upload attachment
$attachment_path = $this->getUploadedFilePath($request->file('attachment'), 'revenues');
if ($attachment_path) {
$request['attachment'] = $attachment_path;
}
$bill = Bill::find($request['bill_id']);
if ($request['currency_code'] == $bill->currency_code) {
if ($request['amount'] > $bill->amount) {
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
return response()->json($message);
} elseif ($request['amount'] == $bill->amount) {
$bill->bill_status_code = 'paid';
} else {
$bill->bill_status_code = 'partial';
}
} else {
$request_bill = new Bill();
$request_bill->amount = (float) $request['amount'];
$request_bill->currency_code = $currency->code;
$request_bill->currency_rate = $currency->rate;
$amount = $request_bill->getConvertedAmount();
if ($amount > $bill->amount) {
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
return response()->json($message);
} elseif ($amount == $bill->amount) {
$bill->bill_status_code = 'paid';
} else {
$bill->bill_status_code = 'partial';
}
}
$bill->save();
$bill_payment = BillPayment::create($request->input());
$request['status_code'] = $bill->bill_status_code;
$request['notify'] = 0;
$desc_date = Date::parse($request['paid_at'])->format($this->getCompanyDateFormat());
$desc_amount = money((float) $request['amount'], $request['currency_code'], true)->format();
$request['description'] = $desc_date . ' ' . $desc_amount;
BillHistory::create($request->input());
$message = trans('messages.success.added', ['type' => trans_choice('general.revenues', 1)]);
return response()->json($message);
}
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
* *

View File

@ -82,141 +82,6 @@ class Invoices extends Controller
return view('incomes.invoices.show', compact('invoice', 'accounts', 'currencies', 'account_currency_code', 'customers', 'categories', 'payment_methods')); return view('incomes.invoices.show', compact('invoice', 'accounts', 'currencies', 'account_currency_code', 'customers', 'categories', 'payment_methods'));
} }
/**
* Show the form for viewing the specified resource.
*
* @param int $invoice_id
*
* @return Response
*/
public function printInvoice($invoice_id)
{
$paid = 0;
$invoice = Invoice::where('id', $invoice_id)->first();
foreach ($invoice->payments as $item) {
$item->default_currency_code = $invoice->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$invoice->paid = $paid;
$invoice->template_path = 'incomes.invoices.invoice';
event(new InvoicePrinting($invoice));
return view($invoice->template_path, compact('invoice'));
}
/**
* Show the form for viewing the specified resource.
*
* @param int $invoice_id
*
* @return Response
*/
public function pdfInvoice($invoice_id)
{
$paid = 0;
$invoice = Invoice::where('id', $invoice_id)->first();
foreach ($invoice->payments as $item) {
$item->default_currency_code = $invoice->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$invoice->paid = $paid;
$invoice->template_path = 'incomes.invoices.invoice';
event(new InvoicePrinting($invoice));
$html = view($invoice->template_path, compact('invoice'))->render();
$pdf = \App::make('dompdf.wrapper');
$pdf->loadHTML($html);
$file_name = 'invoice_'.time().'.pdf';
return $pdf->download($file_name);
}
/**
* Show the form for viewing the specified resource.
*
* @param PaymentRequest $request
*
* @return Response
*/
public function payment(PaymentRequest $request)
{
// Get currency object
$currency = Currency::where('code', $request['currency_code'])->first();
$request['currency_code'] = $currency->code;
$request['currency_rate'] = $currency->rate;
// Upload attachment
$attachment_path = $this->getUploadedFilePath($request->file('attachment'), 'revenues');
if ($attachment_path) {
$request['attachment'] = $attachment_path;
}
$invoice = Invoice::find($request['invoice_id']);
if ($request['currency_code'] == $invoice->currency_code) {
if ($request['amount'] > $invoice->amount) {
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
return response()->json($message);
} elseif ($request['amount'] == $invoice->amount) {
$invoice->invoice_status_code = 'paid';
} else {
$invoice->invoice_status_code = 'partial';
}
} else {
$request_invoice = new Invoice();
$request_invoice->amount = (float) $request['amount'];
$request_invoice->currency_code = $currency->code;
$request_invoice->currency_rate = $currency->rate;
$amount = $request_invoice->getConvertedAmount();
if ($amount > $invoice->amount) {
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
return response()->json($message);
} elseif ($amount == $invoice->amount) {
$invoice->invoice_status_code = 'paid';
} else {
$invoice->invoice_status_code = 'partial';
}
}
$invoice->save();
$invoice_payment = InvoicePayment::create($request->input());
$request['status_code'] = $invoice->invoice_status_code;
$request['notify'] = 0;
$desc_date = Date::parse($request['paid_at'])->format($this->getCompanyDateFormat());
$desc_amount = money((float) $request['amount'], $request['currency_code'], true)->format();
$request['description'] = $desc_date . ' ' . $desc_amount;
InvoiceHistory::create($request->input());
$message = trans('messages.success.added', ['type' => trans_choice('general.revenues', 1)]);
return response()->json($message);
}
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
* *
@ -411,8 +276,6 @@ class Invoices extends Controller
$request['currency_code'] = $currency->code; $request['currency_code'] = $currency->code;
$request['currency_rate'] = $currency->rate; $request['currency_rate'] = $currency->rate;
$request['invoice_status_code'] = 'draft';
// Upload attachment // Upload attachment
$attachment_path = $this->getUploadedFilePath($request->file('attachment'), 'invoices'); $attachment_path = $this->getUploadedFilePath($request->file('attachment'), 'invoices');
@ -527,6 +390,195 @@ class Invoices extends Controller
return redirect('incomes/invoices'); return redirect('incomes/invoices');
} }
/**
* Mark the invoice as sent.
*
* @param int $invoice_id
*
* @return Response
*/
public function markSent($invoice_id)
{
$invoice = Invoice::find($invoice_id);
$invoice->invoice_status_code = 'sent';
$invoice->save();
flash(trans('invoices.messages.marked_sent'))->success();
return redirect()->back();
}
/**
* Mark the invoice as paid.
*
* @param int $invoice_id
*
* @return Response
*/
public function payInvoice($invoice_id)
{
$invoice = Invoice::find($invoice_id);
$paid = 0;
foreach ($invoice->payments as $item) {
$item->default_currency_code = $invoice->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$amount = $invoice->amount - $paid;
$request = new PaymentRequest();
$request['company_id'] = $invoice->company_id;
$request['invoice_id'] = $invoice->id;
$request['account_id'] = setting('general.default_account');
$request['payment_method'] = setting('general.default_payment_method');
$request['currency_code'] = $invoice->currency_code;
$request['amount'] = $amount;
$request['paid_at'] = Date::now();
$request['_token'] = csrf_token();
$this->payment($request);
return redirect()->back();
}
/**
* Print the invoice.
*
* @param int $invoice_id
*
* @return Response
*/
public function printInvoice($invoice_id)
{
$paid = 0;
$invoice = Invoice::find($invoice_id);
foreach ($invoice->payments as $item) {
$item->default_currency_code = $invoice->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$invoice->paid = $paid;
$invoice->template_path = 'incomes.invoices.invoice';
event(new InvoicePrinting($invoice));
return view($invoice->template_path, compact('invoice'));
}
/**
* Download the PDF file of invoice.
*
* @param int $invoice_id
*
* @return Response
*/
public function pdfInvoice($invoice_id)
{
$paid = 0;
$invoice = Invoice::find($invoice_id);
foreach ($invoice->payments as $item) {
$item->default_currency_code = $invoice->currency_code;
$paid += $item->getDynamicConvertedAmount();
}
$invoice->paid = $paid;
$invoice->template_path = 'incomes.invoices.invoice';
event(new InvoicePrinting($invoice));
$html = view($invoice->template_path, compact('invoice'))->render();
$pdf = \App::make('dompdf.wrapper');
$pdf->loadHTML($html);
$file_name = 'invoice_'.time().'.pdf';
return $pdf->download($file_name);
}
/**
* Add payment to the invoice.
*
* @param PaymentRequest $request
*
* @return Response
*/
public function payment(PaymentRequest $request)
{
// Get currency object
$currency = Currency::where('code', $request['currency_code'])->first();
$request['currency_code'] = $currency->code;
$request['currency_rate'] = $currency->rate;
// Upload attachment
$attachment_path = $this->getUploadedFilePath($request->file('attachment'), 'invoices');
if ($attachment_path) {
$request['attachment'] = $attachment_path;
}
$invoice = Invoice::find($request['invoice_id']);
if ($request['currency_code'] == $invoice->currency_code) {
if ($request['amount'] > $invoice->amount) {
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
return response()->json($message);
} elseif ($request['amount'] == $invoice->amount) {
$invoice->invoice_status_code = 'paid';
} else {
$invoice->invoice_status_code = 'partial';
}
} else {
$request_invoice = new Invoice();
$request_invoice->amount = (float) $request['amount'];
$request_invoice->currency_code = $currency->code;
$request_invoice->currency_rate = $currency->rate;
$amount = $request_invoice->getConvertedAmount();
if ($amount > $invoice->amount) {
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
return response()->json($message);
} elseif ($amount == $invoice->amount) {
$invoice->invoice_status_code = 'paid';
} else {
$invoice->invoice_status_code = 'partial';
}
}
$invoice->save();
$invoice_payment = InvoicePayment::create($request->input());
$request['status_code'] = $invoice->invoice_status_code;
$request['notify'] = 0;
$desc_date = Date::parse($request['paid_at'])->format($this->getCompanyDateFormat());
$desc_amount = money((float) $request['amount'], $request['currency_code'], true)->format();
$request['description'] = $desc_date . ' ' . $desc_amount;
InvoiceHistory::create($request->input());
$message = trans('messages.success.added', ['type' => trans_choice('general.revenues', 1)]);
return response()->json($message);
}
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
* *

View File

@ -70,23 +70,23 @@ class ExpenseSummary extends Controller
// Bills // Bills
switch ($status) { switch ($status) {
case 'all': case 'paid':
$bills = Bill::getMonthsOfYear('billed_at'); $bills = BillPayment::monthsOfYear('paid_at')->get();
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'billed_at'); $this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'paid_at');
break; break;
case 'upcoming': case 'upcoming':
$bills = Bill::getMonthsOfYear('due_at'); $bills = Bill::accrued()->monthsOfYear('due_at')->get();
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'due_at'); $this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'due_at');
break; break;
default: default:
$bills = BillPayment::getMonthsOfYear('paid_at'); $bills = Bill::accrued()->monthsOfYear('billed_at')->get();
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'paid_at'); $this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'billed_at');
break; break;
} }
// Payments // Payments
if ($status != 'upcoming') { if ($status != 'upcoming') {
$payments = Payment::getMonthsOfYear('paid_at'); $payments = Payment::monthsOfYear('paid_at')->get();
$this->setAmount($expenses_graph, $totals, $expenses, $payments, 'payment', 'paid_at'); $this->setAmount($expenses_graph, $totals, $expenses, $payments, 'payment', 'paid_at');
} }

View File

@ -98,45 +98,45 @@ class IncomeExpenseSummary extends Controller
// Invoices // Invoices
switch ($status) { switch ($status) {
case 'all': case 'paid':
$invoices = Invoice::getMonthsOfYear('invoiced_at'); $invoices = InvoicePayment::monthsOfYear('paid_at')->get();
$this->setAmount($compares_graph, $totals, $compares, $invoices, 'invoice', 'invoiced_at'); $this->setAmount($compares_graph, $totals, $compares, $invoices, 'invoice', 'paid_at');
break; break;
case 'upcoming': case 'upcoming':
$invoices = Invoice::getMonthsOfYear('due_at'); $invoices = Invoice::accrued()->monthsOfYear('due_at')->get();
$this->setAmount($compares_graph, $totals, $compares, $invoices, 'invoice', 'due_at'); $this->setAmount($compares_graph, $totals, $compares, $invoices, 'invoice', 'due_at');
break; break;
default: default:
$invoices = InvoicePayment::getMonthsOfYear('paid_at'); $invoices = Invoice::accrued()->monthsOfYear('invoiced_at')->get();
$this->setAmount($compares_graph, $totals, $compares, $invoices, 'invoice', 'paid_at'); $this->setAmount($compares_graph, $totals, $compares, $invoices, 'invoice', 'invoiced_at');
break; break;
} }
// Revenues // Revenues
if ($status != 'upcoming') { if ($status != 'upcoming') {
$revenues = Revenue::getMonthsOfYear('paid_at'); $revenues = Revenue::monthsOfYear('paid_at')->get();
$this->setAmount($compares_graph, $totals, $compares, $revenues, 'revenue', 'paid_at'); $this->setAmount($compares_graph, $totals, $compares, $revenues, 'revenue', 'paid_at');
} }
// Bills // Bills
switch ($status) { switch ($status) {
case 'all': case 'paid':
$bills = Bill::getMonthsOfYear('billed_at'); $bills = BillPayment::monthsOfYear('paid_at')->get();
$this->setAmount($compares_graph, $totals, $compares, $bills, 'bill', 'billed_at'); $this->setAmount($compares_graph, $totals, $compares, $bills, 'bill', 'paid_at');
break; break;
case 'upcoming': case 'upcoming':
$bills = Bill::getMonthsOfYear('due_at'); $bills = Bill::accrued()->monthsOfYear('due_at')->get();
$this->setAmount($compares_graph, $totals, $compares, $bills, 'bill', 'due_at'); $this->setAmount($compares_graph, $totals, $compares, $bills, 'bill', 'due_at');
break; break;
default: default:
$bills = BillPayment::getMonthsOfYear('paid_at'); $bills = Bill::accrued()->monthsOfYear('billed_at')->get();
$this->setAmount($compares_graph, $totals, $compares, $bills, 'bill', 'paid_at'); $this->setAmount($compares_graph, $totals, $compares, $bills, 'bill', 'billed_at');
break; break;
} }
// Payments // Payments
if ($status != 'upcoming') { if ($status != 'upcoming') {
$payments = Payment::getMonthsOfYear('paid_at'); $payments = Payment::monthsOfYear('paid_at')->get();
$this->setAmount($compares_graph, $totals, $compares, $payments, 'payment', 'paid_at'); $this->setAmount($compares_graph, $totals, $compares, $payments, 'payment', 'paid_at');
} }

View File

@ -70,23 +70,23 @@ class IncomeSummary extends Controller
// Invoices // Invoices
switch ($status) { switch ($status) {
case 'all': case 'paid':
$invoices = Invoice::getMonthsOfYear('invoiced_at'); $invoices = InvoicePayment::monthsOfYear('paid_at')->get();
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'invoiced_at'); $this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'paid_at');
break; break;
case 'upcoming': case 'upcoming':
$invoices = Invoice::getMonthsOfYear('due_at'); $invoices = Invoice::accrued()->monthsOfYear('due_at')->get();
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'due_at'); $this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'due_at');
break; break;
default: default:
$invoices = InvoicePayment::getMonthsOfYear('paid_at'); $invoices = Invoice::accrued()->monthsOfYear('invoiced_at')->get();
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'paid_at'); $this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'invoiced_at');
break; break;
} }
// Revenues // Revenues
if ($status != 'upcoming') { if ($status != 'upcoming') {
$revenues = Revenue::getMonthsOfYear('paid_at'); $revenues = Revenue::monthsOfYear('paid_at')->get();
$this->setAmount($incomes_graph, $totals, $incomes, $revenues, 'revenue', 'paid_at'); $this->setAmount($incomes_graph, $totals, $incomes, $revenues, 'revenue', 'paid_at');
} }

View File

@ -3,6 +3,9 @@
namespace App\Listeners\Updates; namespace App\Listeners\Updates;
use App\Events\UpdateFinished; use App\Events\UpdateFinished;
use App\Models\Company\Company;
use App\Models\Expense\Bill;
use App\Models\Expense\BillStatus;
class Version108 extends Listener class Version108 extends Listener
{ {
@ -23,6 +26,13 @@ class Version108 extends Listener
return; return;
} }
$this->updateSettings();
$this->updateBills();
}
private function updateSettings()
{
// Set new invoice settings
setting(['general.invoice_number_prefix' => setting('general.invoice_prefix', 'INV-')]); setting(['general.invoice_number_prefix' => setting('general.invoice_prefix', 'INV-')]);
setting(['general.invoice_number_digit' => setting('general.invoice_digit', '5')]); setting(['general.invoice_number_digit' => setting('general.invoice_digit', '5')]);
setting(['general.invoice_number_next' => setting('general.invoice_start', '1')]); setting(['general.invoice_number_next' => setting('general.invoice_start', '1')]);
@ -33,4 +43,48 @@ class Version108 extends Listener
setting()->save(); setting()->save();
} }
private function updateBills()
{
// Create new bill statuses
$companies = Company::all();
foreach ($companies as $company) {
$rows = [
[
'company_id' => $company->id,
'name' => trans('bills.status.draft'),
'code' => 'draft',
],
[
'company_id' => $company->id,
'name' => trans('bills.status.received'),
'code' => 'received',
],
];
foreach ($rows as $row) {
BillStatus::create($row);
}
}
$bills = Bill::all();
foreach ($bills as $bill) {
if (($bill->bill_status_code != 'new') || ($bill->bill_status_code != 'updated')) {
continue;
}
$bill->bill_status_code = 'draft';
$bill->save();
}
$new = BillStatus::where('code', 'new');
$new->delete();
$new->forceDelete();
$updated = BillStatus::where('code', 'updated');
$updated->delete();
$updated->forceDelete();
}
} }

View File

@ -79,6 +79,21 @@ class Bill extends Model
return $this->hasMany('App\Models\Expense\BillHistory'); return $this->hasMany('App\Models\Expense\BillHistory');
} }
public function scopeDue($query, $date)
{
return $query->where('due_at', '=', $date);
}
public function scopeLatest($query)
{
return $query->orderBy('paid_at', 'desc');
}
public function scopeAccrued($query)
{
return $query->where('bill_status_code', '!=', 'new');
}
/** /**
* Convert amount to double. * Convert amount to double.
* *
@ -100,9 +115,4 @@ class Bill extends Model
{ {
$this->attributes['currency_rate'] = (double) $value; $this->attributes['currency_rate'] = (double) $value;
} }
public function scopeDue($query, $date)
{
return $query->where('due_at', '=', $date);
}
} }

View File

@ -84,6 +84,21 @@ class Invoice extends Model
return $this->hasMany('App\Models\Income\InvoiceHistory'); return $this->hasMany('App\Models\Income\InvoiceHistory');
} }
public function scopeDue($query, $date)
{
return $query->where('due_at', '=', $date);
}
public function scopeLatest($query)
{
return $query->orderBy('paid_at', 'desc');
}
public function scopeAccrued($query)
{
return $query->where('invoice_status_code', '!=', 'draft');
}
/** /**
* Convert amount to double. * Convert amount to double.
* *
@ -105,9 +120,4 @@ class Invoice extends Model
{ {
$this->attributes['currency_rate'] = (double) $value; $this->attributes['currency_rate'] = (double) $value;
} }
public function scopeDue($query, $date)
{
return $query->where('due_at', '=', $date);
}
} }

View File

@ -23,7 +23,7 @@ trait DateTime
return str_replace(' ', $date_separator, $date_format); return str_replace(' ', $date_separator, $date_format);
} }
public static function getMonthsOfYear($field) public function scopeMonthsOfYear($query, $field)
{ {
$year = request('year'); $year = request('year');
@ -35,7 +35,7 @@ trait DateTime
$start = Date::parse($year . '-01-01')->format('Y-m-d'); $start = Date::parse($year . '-01-01')->format('Y-m-d');
$end = Date::parse($year . '-12-31')->format('Y-m-d'); $end = Date::parse($year . '-12-31')->format('Y-m-d');
return static::whereBetween($field, [$start, $end])->get(); return $query->whereBetween($field, [$start, $end]);
} }
public function getTimezones() public function getTimezones()

View File

@ -30,13 +30,13 @@ class BillStatuses extends Seeder
$rows = [ $rows = [
[ [
'company_id' => $company_id, 'company_id' => $company_id,
'name' => trans('bills.status.new'), 'name' => trans('bills.status.draft'),
'code' => 'new', 'code' => 'draft',
], ],
[ [
'company_id' => $company_id, 'company_id' => $company_id,
'name' => trans('bills.status.updated'), 'name' => trans('bills.status.received'),
'code' => 'updated', 'code' => 'received',
], ],
[ [
'company_id' => $company_id, 'company_id' => $company_id,

View File

@ -23,14 +23,19 @@ return [
'histories' => 'Histories', 'histories' => 'Histories',
'payments' => 'Payments', 'payments' => 'Payments',
'add_payment' => 'Add Payment', 'add_payment' => 'Add Payment',
'mark_received' => 'Mark Received',
'download_pdf' => 'Download PDF', 'download_pdf' => 'Download PDF',
'send_mail' => 'Send Email', 'send_mail' => 'Send Email',
'status' => [ 'status' => [
'new' => 'New', 'draft' => 'Draft',
'updated' => 'Updated', 'received' => 'Received',
'partial' => 'Partial', 'partial' => 'Partial',
'paid' => 'Paid', 'paid' => 'Paid',
], ],
'messages' => [
'received' => 'Bill marked as received successfully!',
],
]; ];

View File

@ -91,6 +91,7 @@ return [
'upcoming' => 'Upcoming', 'upcoming' => 'Upcoming',
'created' => 'Created', 'created' => 'Created',
'id' => 'ID', 'id' => 'ID',
'more_actions' => 'More Actions',
'title' => [ 'title' => [
'new' => 'New :type', 'new' => 'New :type',

View File

@ -22,6 +22,8 @@ return [
'histories' => 'Histories', 'histories' => 'Histories',
'payments' => 'Payments', 'payments' => 'Payments',
'add_payment' => 'Add Payment', 'add_payment' => 'Add Payment',
'mark_paid' => 'Mark Paid',
'mark_sent' => 'Mark Sent',
'download_pdf' => 'Download PDF', 'download_pdf' => 'Download PDF',
'send_mail' => 'Send Email', 'send_mail' => 'Send Email',
@ -34,4 +36,8 @@ return [
'paid' => 'Paid', 'paid' => 'Paid',
], ],
'messages' => [
'marked_sent' => 'Invoice marked as sent successfully!',
],
]; ];

View File

@ -17,7 +17,7 @@
<span class="title-filter hidden-xs">{{ trans('general.search') }}:</span> <span class="title-filter hidden-xs">{{ trans('general.search') }}:</span>
{!! Form::text('search', request('search'), ['class' => 'form-control input-filter input-sm', 'placeholder' => trans('general.search_placeholder')]) !!} {!! Form::text('search', request('search'), ['class' => 'form-control input-filter input-sm', 'placeholder' => trans('general.search_placeholder')]) !!}
{!! Form::select('vendor', $vendors, request('vendor'), ['class' => 'form-control input-filter input-sm']) !!} {!! Form::select('vendor', $vendors, request('vendor'), ['class' => 'form-control input-filter input-sm']) !!}
{!! Form::select('status', $status, request('status'), ['class' => 'form-control input-filter input-sm']) !!} {!! Form::select('status', $statuses, request('status'), ['class' => 'form-control input-filter input-sm']) !!}
{!! Form::button('<span class="fa fa-filter"></span> &nbsp;' . trans('general.filter'), ['type' => 'submit', 'class' => 'btn btn-sm btn-default btn-filter']) !!} {!! Form::button('<span class="fa fa-filter"></span> &nbsp;' . trans('general.filter'), ['type' => 'submit', 'class' => 'btn btn-sm btn-default btn-filter']) !!}
</div> </div>
<div class="pull-right"> <div class="pull-right">

View File

@ -150,12 +150,21 @@
<a href="{{ url('expenses/bills/' . $bill->id . '/print') }}" target="_blank" class="btn btn-default"> <a href="{{ url('expenses/bills/' . $bill->id . '/print') }}" target="_blank" class="btn btn-default">
<i class="fa fa-print"></i>&nbsp; {{ trans('general.print') }} <i class="fa fa-print"></i>&nbsp; {{ trans('general.print') }}
</a> </a>
<button type="button" id="button-pdf" class="btn btn-default" data-toggle="tooltip" title="{{ trans('bills.download_pdf') }}"> <div class="btn-group dropup">
<i class="fa fa-file-pdf-o"></i>&nbsp; {{ trans('general.download') }} <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="fa fa-chevron-circle-up"></i>&nbsp;{{ trans('general.more_actions') }}</button>
</button> <ul class="dropdown-menu" role="menu">
<button type="button" id="button-payment" class="btn btn-success"> <li><a href="#" id="button-payment">{{ trans('bills.add_payment') }}</a></li>
<i class="fa fa-credit-card"></i>&nbsp; {{ trans('bills.add_payment') }} @permission('update-expenses-bills')
</button> <li><a href="{{ url('expenses/bills/' . $bill->id . '/received') }}">{{ trans('bills.mark_received') }}</a></li>
@endpermission
<li class="divider"></li>
<li><a href="{{ url('expenses/bills/' . $bill->id . '/pdf') }}">{{ trans('bills.download_pdf') }}</a></li>
<li class="divider"></li>
@permission('delete-expenses-bills')
<li>{!! Form::deleteLink($bill, 'expenses/bills') !!}</li>
@endpermission
</ul>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -150,15 +150,26 @@
<a href="{{ url('incomes/invoices/' . $invoice->id . '/print') }}" target="_blank" class="btn btn-default"> <a href="{{ url('incomes/invoices/' . $invoice->id . '/print') }}" target="_blank" class="btn btn-default">
<i class="fa fa-print"></i>&nbsp; {{ trans('general.print') }} <i class="fa fa-print"></i>&nbsp; {{ trans('general.print') }}
</a> </a>
<button type="button" id="button-email" class="btn btn-default" data-toggle="tooltip" title="{{ trans('invoices.send_mail') }}"> <div class="btn-group dropup">
<i class="fa fa-envelope-o"></i>&nbsp; {{ trans('general.send') }} <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="fa fa-chevron-circle-up"></i>&nbsp;{{ trans('general.more_actions') }}</button>
</button> <ul class="dropdown-menu" role="menu">
<button type="button" id="button-pdf" class="btn btn-default" data-toggle="tooltip" title="{{ trans('invoices.download_pdf') }}"> @permission('update-incomes-invoices')
<i class="fa fa-file-pdf-o"></i>&nbsp; {{ trans('general.download') }} <li><a href="{{ url('incomes/invoices/' . $invoice->id . '/pay') }}">{{ trans('invoices.mark_paid') }}</a></li>
</button> @endpermission
<button type="button" id="button-payment" class="btn btn-success"> <li><a href="#" id="button-payment">{{ trans('invoices.add_payment') }}</a></li>
<i class="fa fa-credit-card"></i>&nbsp; {{ trans('invoices.add_payment') }} <li class="divider"></li>
</button> @permission('update-incomes-invoices')
<li><a href="{{ url('incomes/invoices/' . $invoice->id . '/sent') }}">{{ trans('invoices.mark_sent') }}</a></li>
@endpermission
<li><a href="#" id="button-email">{{ trans('invoices.send_mail') }}</a></li>
<li class="divider"></li>
<li><a href="{{ url('incomes/invoices/' . $invoice->id . '/pdf') }}">{{ trans('invoices.download_pdf') }}</a></li>
<li class="divider"></li>
@permission('delete-incomes-invoices')
<li>{!! Form::deleteLink($invoice, 'incomes/invoices') !!}</li>
@endpermission
</ul>
</div>
</div> </div>
</div> </div>
</section> </section>

View File

@ -7,8 +7,8 @@
<div class="box box-success"> <div class="box box-success">
<div class="box-header"> <div class="box-header">
<div class="pull-left" style="margin-left: 23px"> <div class="pull-left" style="margin-left: 23px">
<a href="{{ url('reports/expense-summary') }}?status=all"><span class="badge @if (request('status') == 'all') bg-green @else bg-default @endif">{{ trans('general.all') }}</span></a> <a href="{{ url('reports/expense-summary') }}"><span class="badge @if (request('status') == '') bg-green @else bg-default @endif">{{ trans('general.all') }}</span></a>
<a href="{{ url('reports/expense-summary') }}"><span class="badge @if (request('status') == '') bg-green @else bg-default @endif">{{ trans('bills.paid') }}</span></a> <a href="{{ url('reports/expense-summary') }}?status=paid"><span class="badge @if (request('status') == 'paid') bg-green @else bg-default @endif">{{ trans('bills.paid') }}</span></a>
<a href="{{ url('reports/expense-summary') }}?status=upcoming"><span class="badge @if (request('status') == 'upcoming') bg-green @else bg-default @endif">{{ trans('dashboard.payables') }}</span></a> <a href="{{ url('reports/expense-summary') }}?status=upcoming"><span class="badge @if (request('status') == 'upcoming') bg-green @else bg-default @endif">{{ trans('dashboard.payables') }}</span></a>
</div> </div>
{!! Form::open(['url' => 'reports/expense-summary', 'role' => 'form', 'method' => 'GET']) !!} {!! Form::open(['url' => 'reports/expense-summary', 'role' => 'form', 'method' => 'GET']) !!}

View File

@ -7,8 +7,8 @@
<div class="box box-success"> <div class="box box-success">
<div class="box-header"> <div class="box-header">
<div class="pull-left" style="margin-left: 23px"> <div class="pull-left" style="margin-left: 23px">
<a href="{{ url('reports/income-expense-summary') }}?status=all"><span class="badge @if (request('status') == 'all') bg-green @else bg-default @endif">{{ trans('general.all') }}</span></a> <a href="{{ url('reports/income-expense-summary') }}"><span class="badge @if (request('status') == '') bg-green @else bg-default @endif">{{ trans('general.all') }}</span></a>
<a href="{{ url('reports/income-expense-summary') }}"><span class="badge @if (request('status') == '') bg-green @else bg-default @endif">{{ trans('invoices.paid') }}</span></a> <a href="{{ url('reports/income-expense-summary') }}?status=paid"><span class="badge @if (request('status') == 'paid') bg-green @else bg-default @endif">{{ trans('invoices.paid') }}</span></a>
<a href="{{ url('reports/income-expense-summary') }}?status=upcoming"><span class="badge @if (request('status') == 'upcoming') bg-green @else bg-default @endif">{{ trans('general.upcoming') }}</span></a> <a href="{{ url('reports/income-expense-summary') }}?status=upcoming"><span class="badge @if (request('status') == 'upcoming') bg-green @else bg-default @endif">{{ trans('general.upcoming') }}</span></a>
</div> </div>
{!! Form::open(['url' => 'reports/income-expense-summary', 'role' => 'form', 'method' => 'GET']) !!} {!! Form::open(['url' => 'reports/income-expense-summary', 'role' => 'form', 'method' => 'GET']) !!}

View File

@ -7,8 +7,8 @@
<div class="box box-success"> <div class="box box-success">
<div class="box-header"> <div class="box-header">
<div class="pull-left" style="margin-left: 23px"> <div class="pull-left" style="margin-left: 23px">
<a href="{{ url('reports/income-summary') }}?status=all"><span class="badge @if (request('status') == 'all') bg-green @else bg-default @endif">{{ trans('general.all') }}</span></a> <a href="{{ url('reports/income-summary') }}"><span class="badge @if (request('status') == '') bg-green @else bg-default @endif">{{ trans('general.all') }}</span></a>
<a href="{{ url('reports/income-summary') }}"><span class="badge @if (request('status') == '') bg-green @else bg-default @endif">{{ trans('invoices.paid') }}</span></a> <a href="{{ url('reports/income-summary') }}?status=paid"><span class="badge @if (request('status') == 'paid') bg-green @else bg-default @endif">{{ trans('invoices.paid') }}</span></a>
<a href="{{ url('reports/income-summary') }}?status=upcoming"><span class="badge @if (request('status') == 'upcoming') bg-green @else bg-default @endif">{{ trans('dashboard.receivables') }}</span></a> <a href="{{ url('reports/income-summary') }}?status=upcoming"><span class="badge @if (request('status') == 'upcoming') bg-green @else bg-default @endif">{{ trans('dashboard.receivables') }}</span></a>
</div> </div>
{!! Form::open(['url' => 'reports/income-summary', 'role' => 'form', 'method' => 'GET']) !!} {!! Form::open(['url' => 'reports/income-summary', 'role' => 'form', 'method' => 'GET']) !!}

View File

@ -44,6 +44,8 @@ Route::group(['middleware' => 'language'], function () {
Route::group(['prefix' => 'incomes'], function () { Route::group(['prefix' => 'incomes'], function () {
Route::get('customers/currency', 'Incomes\Customers@currency'); Route::get('customers/currency', 'Incomes\Customers@currency');
Route::resource('customers', 'Incomes\Customers'); Route::resource('customers', 'Incomes\Customers');
Route::get('invoices/{id}/sent', 'Incomes\Invoices@markSent');
Route::get('invoices/{id}/pay', 'Incomes\Invoices@payInvoice');
Route::get('invoices/{id}/print', 'Incomes\Invoices@printInvoice'); Route::get('invoices/{id}/print', 'Incomes\Invoices@printInvoice');
Route::get('invoices/{id}/pdf', 'Incomes\Invoices@pdfInvoice'); Route::get('invoices/{id}/pdf', 'Incomes\Invoices@pdfInvoice');
Route::post('invoices/payment', 'Incomes\Invoices@payment'); Route::post('invoices/payment', 'Incomes\Invoices@payment');
@ -54,6 +56,7 @@ Route::group(['middleware' => 'language'], function () {
Route::group(['prefix' => 'expenses'], function () { Route::group(['prefix' => 'expenses'], function () {
Route::resource('payments', 'Expenses\Payments'); Route::resource('payments', 'Expenses\Payments');
Route::get('bills/{id}/received', 'Expenses\Bills@markReceived');
Route::get('bills/{id}/print', 'Expenses\Bills@printBill'); Route::get('bills/{id}/print', 'Expenses\Bills@printBill');
Route::get('bills/{id}/pdf', 'Expenses\Bills@pdfBill'); Route::get('bills/{id}/pdf', 'Expenses\Bills@pdfBill');
Route::post('bills/payment', 'Expenses\Bills@payment'); Route::post('bills/payment', 'Expenses\Bills@payment');