2013-12-25 22:34:42 +01:00
< ? php namespace ninja\repositories ;
use Invoice ;
use InvoiceItem ;
2014-05-20 23:40:09 +02:00
use Invitation ;
2013-12-25 22:34:42 +01:00
use Product ;
use Utils ;
2013-12-29 00:33:48 +01:00
use TaxRate ;
2013-12-25 22:34:42 +01:00
class InvoiceRepository
{
public function getInvoices ( $accountId , $clientPublicId = false , $filter = false )
{
$query = \DB :: table ( 'invoices' )
-> join ( 'clients' , 'clients.id' , '=' , 'invoices.client_id' )
2014-02-16 21:32:25 +01:00
-> join ( 'invoice_statuses' , 'invoice_statuses.id' , '=' , 'invoices.invoice_status_id' )
-> join ( 'contacts' , 'contacts.client_id' , '=' , 'clients.id' )
2014-05-20 23:40:09 +02:00
-> where ( 'invoices.account_id' , '=' , $accountId )
-> where ( 'clients.deleted_at' , '=' , null )
2014-06-02 18:21:47 +02:00
-> where ( 'contacts.deleted_at' , '=' , null )
2013-12-30 21:17:45 +01:00
-> where ( 'invoices.is_recurring' , '=' , false )
-> where ( 'contacts.is_primary' , '=' , true )
2014-10-14 21:04:48 +02:00
-> select ( 'clients.public_id as client_public_id' , 'invoice_number' , 'invoice_status_id' , 'clients.name as client_name' , 'invoices.public_id' , 'amount' , 'invoices.balance' , 'invoice_date' , 'due_date' , 'invoice_statuses.name as invoice_status_name' , 'clients.currency_id' , 'contacts.first_name' , 'contacts.last_name' , 'contacts.email' , 'quote_id' , 'quote_invoice_id' );
2013-12-25 22:34:42 +01:00
2014-07-30 09:08:01 +02:00
if ( ! \Session :: get ( 'show_trash:invoice' ))
2014-02-18 22:56:18 +01:00
{
$query -> where ( 'invoices.deleted_at' , '=' , null );
}
2013-12-25 22:34:42 +01:00
if ( $clientPublicId )
{
$query -> where ( 'clients.public_id' , '=' , $clientPublicId );
}
if ( $filter )
{
$query -> where ( function ( $query ) use ( $filter )
{
$query -> where ( 'clients.name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'invoices.invoice_number' , 'like' , '%' . $filter . '%' )
2014-02-26 17:08:40 +01:00
-> orWhere ( 'invoice_statuses.name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'contacts.first_name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'contacts.last_name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'contacts.email' , 'like' , '%' . $filter . '%' );
2013-12-25 22:34:42 +01:00
});
}
return $query ;
}
public function getRecurringInvoices ( $accountId , $clientPublicId = false , $filter = false )
{
$query = \DB :: table ( 'invoices' )
-> join ( 'clients' , 'clients.id' , '=' , 'invoices.client_id' )
2014-03-23 21:56:19 +01:00
-> join ( 'frequencies' , 'frequencies.id' , '=' , 'invoices.frequency_id' )
-> join ( 'contacts' , 'contacts.client_id' , '=' , 'clients.id' )
-> where ( 'invoices.account_id' , '=' , $accountId )
2014-05-20 23:40:09 +02:00
-> where ( 'invoices.is_quote' , '=' , false )
2014-02-18 22:56:18 +01:00
-> where ( 'clients.deleted_at' , '=' , null )
2013-12-25 22:34:42 +01:00
-> where ( 'invoices.is_recurring' , '=' , true )
2013-12-30 21:17:45 +01:00
-> where ( 'contacts.is_primary' , '=' , true )
2014-03-23 21:56:19 +01:00
-> select ( 'clients.public_id as client_public_id' , 'clients.name as client_name' , 'invoices.public_id' , 'amount' , 'frequencies.name as frequency' , 'start_date' , 'end_date' , 'clients.currency_id' , 'contacts.first_name' , 'contacts.last_name' , 'contacts.email' );
2013-12-25 22:34:42 +01:00
if ( $clientPublicId )
{
$query -> where ( 'clients.public_id' , '=' , $clientPublicId );
}
2014-07-30 09:08:01 +02:00
if ( ! \Session :: get ( 'show_trash:invoice' ))
2014-02-18 22:56:18 +01:00
{
$query -> where ( 'invoices.deleted_at' , '=' , null );
}
2013-12-25 22:34:42 +01:00
if ( $filter )
{
$query -> where ( function ( $query ) use ( $filter )
{
$query -> where ( 'clients.name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'invoices.invoice_number' , 'like' , '%' . $filter . '%' );
});
}
return $query ;
}
2014-05-17 21:29:57 +02:00
public function getDatatable ( $accountId , $clientPublicId = null , $entityType , $search )
{
2014-05-20 23:40:09 +02:00
$query = $this -> getInvoices ( $accountId , $clientPublicId , $search )
-> where ( 'invoices.is_quote' , '=' , $entityType == ENTITY_QUOTE ? true : false );
2014-05-17 21:29:57 +02:00
$table = \Datatable :: query ( $query );
if ( ! $clientPublicId )
{
$table -> addColumn ( 'checkbox' , function ( $model ) { return '<input type="checkbox" name="ids[]" value="' . $model -> public_id . '">' ; });
}
$table -> addColumn ( " invoice_number " , function ( $model ) use ( $entityType ) { return link_to ( " { $entityType } s/ " . $model -> public_id . '/edit' , $model -> invoice_number ); });
if ( ! $clientPublicId )
{
$table -> addColumn ( 'client_name' , function ( $model ) { return link_to ( 'clients/' . $model -> client_public_id , Utils :: getClientDisplayName ( $model )); });
}
$table -> addColumn ( " invoice_date " , function ( $model ) { return Utils :: fromSqlDate ( $model -> invoice_date ); })
-> addColumn ( 'amount' , function ( $model ) { return Utils :: formatMoney ( $model -> amount , $model -> currency_id ); });
if ( $entityType == ENTITY_INVOICE )
{
$table -> addColumn ( 'balance' , function ( $model ) { return Utils :: formatMoney ( $model -> balance , $model -> currency_id ); });
}
return $table -> addColumn ( 'due_date' , function ( $model ) { return Utils :: fromSqlDate ( $model -> due_date ); })
-> addColumn ( 'invoice_status_name' , function ( $model ) { return $model -> invoice_status_name ; })
-> addColumn ( 'dropdown' , function ( $model ) use ( $entityType )
{
$str = ' < div class = " btn-group tr-action " style = " visibility:hidden; " >
< button type = " button " class = " btn btn-xs btn-default dropdown-toggle " data - toggle = " dropdown " >
'.trans(' texts . select ').' < span class = " caret " ></ span >
</ button >
< ul class = " dropdown-menu " role = " menu " >
2014-05-20 23:40:09 +02:00
< li >< a href = " ' . \ URL::to( " { $entityType } s / " . $model->public_id .'/edit') . ' " > '.trans("texts.edit_{$entityType}").' </ a ></ li >
2014-05-22 20:29:29 +02:00
< li >< a href = " ' . \ URL::to( " { $entityType } s / " . $model->public_id .'/clone') . ' " > '.trans("texts.clone_{$entityType}").' </ a ></ li >
2014-10-14 21:04:48 +02:00
< li class = " divider " ></ li > ' ;
2014-05-20 23:40:09 +02:00
2014-10-14 21:04:48 +02:00
if ( $model -> invoice_status_id < INVOICE_STATUS_SENT )
2014-05-20 23:40:09 +02:00
{
2014-10-14 21:04:48 +02:00
$str .= '<li><a href="javascript:markEntity(' . $model -> public_id . ', ' . INVOICE_STATUS_SENT . ')">' . trans ( " texts.mark_sent " ) . '</a></li>' ;
}
if ( $entityType == ENTITY_INVOICE )
2014-05-20 23:40:09 +02:00
{
2014-10-14 21:04:48 +02:00
if ( $model -> invoice_status_id < INVOICE_STATUS_PAID )
{
$str .= '<li><a href="' . \URL :: to ( 'payments/create/' . $model -> client_public_id . '/' . $model -> public_id ) . '">' . trans ( 'texts.enter_payment' ) . '</a></li>' ;
}
if ( $model -> quote_id )
{
$str .= '<li><a href="' . \URL :: to ( " quotes/ { $model -> quote_id } /edit " ) . '">' . trans ( " texts.view_quote " ) . '</a></li>' ;
}
2014-05-20 23:40:09 +02:00
}
2014-10-14 21:04:48 +02:00
else if ( $entityType == ENTITY_QUOTE )
{
if ( $model -> quote_invoice_id )
{
$str .= '<li><a href="' . \URL :: to ( " invoices/ { $model -> quote_invoice_id } /edit " ) . '">' . trans ( " texts.view_invoice " ) . '</a></li>' ;
}
}
return $str . ' < li class = " divider " ></ li >
< li >< a href = " javascript:archiveEntity(' . $model->public_id . ') " > '.trans("texts.archive_{$entityType}").' </ a ></ li >
< li >< a href = " javascript:deleteEntity(' . $model->public_id . ') " > '.trans("texts.delete_{$entityType}").' </ a ></ li >
</ ul >
</ div > ' ;
})
-> make ();
2014-05-17 21:29:57 +02:00
}
2014-01-01 16:23:32 +01:00
public function getErrors ( $input )
{
$contact = ( array ) $input -> client -> contacts [ 0 ];
$rules = [ 'email' => 'required|email' ];
2014-07-27 22:31:41 +02:00
$validator = \Validator :: make ( $contact , $rules );
2014-01-01 16:23:32 +01:00
2014-07-27 22:31:41 +02:00
if ( $validator -> fails ())
{
return $validator ;
}
2014-01-01 16:23:32 +01:00
2014-07-27 22:31:41 +02:00
$invoice = ( array ) $input ;
$invoiceId = isset ( $invoice [ 'public_id' ]) && $invoice [ 'public_id' ] ? Invoice :: getPrivateId ( $invoice [ 'public_id' ]) : null ;
$rules = [ 'invoice_number' => 'required|unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . \Auth :: user () -> account_id ];
2014-01-14 12:52:56 +01:00
2014-07-27 22:31:41 +02:00
if ( $invoice [ 'is_recurring' ] && $invoice [ 'start_date' ] && $invoice [ 'end_date' ])
{
$rules [ 'end_date' ] = 'after:' . $invoice [ 'start_date' ];
}
2014-01-14 12:52:56 +01:00
2014-07-27 22:31:41 +02:00
$validator = \Validator :: make ( $invoice , $rules );
2014-01-01 16:23:32 +01:00
2014-07-27 22:31:41 +02:00
if ( $validator -> fails ())
{
return $validator ;
}
2014-01-01 16:23:32 +01:00
2014-07-27 22:31:41 +02:00
return false ;
2014-01-01 16:23:32 +01:00
}
2014-05-20 23:40:09 +02:00
public function save ( $publicId , $data , $entityType )
2013-12-25 22:34:42 +01:00
{
if ( $publicId )
{
$invoice = Invoice :: scope ( $publicId ) -> firstOrFail ();
}
else
{
$invoice = Invoice :: createNew ();
2014-05-20 23:40:09 +02:00
if ( $entityType == ENTITY_QUOTE )
{
$invoice -> is_quote = true ;
}
2013-12-25 22:34:42 +01:00
}
$invoice -> client_id = $data [ 'client_id' ];
2014-01-14 12:52:56 +01:00
$invoice -> discount = Utils :: parseFloat ( $data [ 'discount' ]);
2013-12-25 22:34:42 +01:00
$invoice -> invoice_number = trim ( $data [ 'invoice_number' ]);
2014-03-10 19:22:40 +01:00
$invoice -> is_recurring = $data [ 'is_recurring' ] ? true : false ;
2014-05-25 20:38:40 +02:00
$invoice -> invoice_date = Utils :: toSqlDate ( $data [ 'invoice_date' ]);
if ( $invoice -> is_recurring )
{
$invoice -> frequency_id = $data [ 'frequency_id' ] ? $data [ 'frequency_id' ] : 0 ;
$invoice -> start_date = Utils :: toSqlDate ( $data [ 'start_date' ]);
$invoice -> end_date = Utils :: toSqlDate ( $data [ 'end_date' ]);
$invoice -> due_date = null ;
}
else
{
$invoice -> due_date = Utils :: toSqlDate ( $data [ 'due_date' ]);
$invoice -> frequency_id = 0 ;
$invoice -> start_date = null ;
$invoice -> end_date = null ;
}
2013-12-25 22:34:42 +01:00
$invoice -> terms = trim ( $data [ 'terms' ]);
2013-12-30 21:17:45 +01:00
$invoice -> public_notes = trim ( $data [ 'public_notes' ]);
2013-12-25 22:34:42 +01:00
$invoice -> po_number = trim ( $data [ 'po_number' ]);
2014-02-19 20:42:57 +01:00
$invoice -> invoice_design_id = $data [ 'invoice_design_id' ];
2014-04-12 20:55:40 +02:00
if ( isset ( $data [ 'tax_name' ]) && isset ( $data [ 'tax_rate' ]) && Utils :: parseFloat ( $data [ 'tax_rate' ]) > 0 )
2013-12-25 22:34:42 +01:00
{
2014-01-14 12:52:56 +01:00
$invoice -> tax_rate = Utils :: parseFloat ( $data [ 'tax_rate' ]);
2014-01-01 16:23:32 +01:00
$invoice -> tax_name = trim ( $data [ 'tax_name' ]);
2014-01-01 00:50:13 +01:00
}
else
{
$invoice -> tax_rate = 0 ;
$invoice -> tax_name = '' ;
2013-12-25 22:34:42 +01:00
}
2014-01-01 00:50:13 +01:00
2013-12-31 20:49:54 +01:00
$total = 0 ;
2013-12-25 22:34:42 +01:00
foreach ( $data [ 'invoice_items' ] as $item )
{
2014-07-20 12:38:42 +02:00
if ( ! $item -> cost && ! $item -> product_key && ! $item -> notes )
2013-12-25 22:34:42 +01:00
{
continue ;
}
2014-02-01 21:01:32 +01:00
$invoiceItemCost = Utils :: parseFloat ( $item -> cost );
$invoiceItemQty = Utils :: parseFloat ( $item -> qty );
$invoiceItemTaxRate = 0 ;
2013-12-25 22:34:42 +01:00
2014-01-14 12:52:56 +01:00
if ( isset ( $item -> tax_rate ) && Utils :: parseFloat ( $item -> tax_rate ) > 0 )
2013-12-29 00:33:48 +01:00
{
2014-02-01 21:01:32 +01:00
$invoiceItemTaxRate = Utils :: parseFloat ( $item -> tax_rate );
2013-12-29 00:33:48 +01:00
}
2014-02-01 21:01:32 +01:00
$lineTotal = $invoiceItemCost * $invoiceItemQty ;
2014-06-01 15:35:19 +02:00
$total += round ( $lineTotal + ( $lineTotal * $invoiceItemTaxRate / 100 ), 2 );
2013-12-31 20:49:54 +01:00
}
if ( $invoice -> discount > 0 )
{
$total *= ( 100 - $invoice -> discount ) / 100 ;
2013-12-25 22:34:42 +01:00
}
2014-07-23 17:02:56 +02:00
$invoice -> custom_value1 = round ( $data [ 'custom_value1' ], 2 );
$invoice -> custom_value2 = round ( $data [ 'custom_value2' ], 2 );
2014-07-20 12:38:42 +02:00
$invoice -> custom_taxes1 = $data [ 'custom_taxes1' ] ? true : false ;
$invoice -> custom_taxes2 = $data [ 'custom_taxes2' ] ? true : false ;
// custom fields charged taxes
if ( $invoice -> custom_value1 && $invoice -> custom_taxes1 ) {
$total += $invoice -> custom_value1 ;
}
if ( $invoice -> custom_value2 && $invoice -> custom_taxes2 ) {
$total += $invoice -> custom_value2 ;
}
2013-12-31 20:49:54 +01:00
$total += $total * $invoice -> tax_rate / 100 ;
2014-06-01 15:35:19 +02:00
$total = round ( $total , 2 );
2013-12-31 20:49:54 +01:00
2014-07-20 12:38:42 +02:00
// custom fields not charged taxes
if ( $invoice -> custom_value1 && ! $invoice -> custom_taxes1 ) {
$total += $invoice -> custom_value1 ;
}
if ( $invoice -> custom_value2 && ! $invoice -> custom_taxes2 ) {
$total += $invoice -> custom_value2 ;
}
2014-04-03 19:54:06 +02:00
if ( $publicId )
{
$invoice -> balance = $total - ( $invoice -> amount - $invoice -> balance );
}
else
{
$invoice -> balance = $total ;
}
$invoice -> amount = $total ;
2013-12-31 20:49:54 +01:00
$invoice -> save ();
2014-02-01 21:01:32 +01:00
$invoice -> invoice_items () -> forceDelete ();
foreach ( $data [ 'invoice_items' ] as $item )
{
2014-07-20 12:38:42 +02:00
if ( ! $item -> cost && ! $item -> product_key && ! $item -> notes )
2014-02-01 21:01:32 +01:00
{
continue ;
}
if ( $item -> product_key )
{
$product = Product :: findProductByKey ( trim ( $item -> product_key ));
if ( ! $product )
{
$product = Product :: createNew ();
$product -> product_key = trim ( $item -> product_key );
}
2014-04-23 23:48:09 +02:00
if ( \Auth :: user () -> account -> update_products )
{
$product -> notes = $item -> notes ;
$product -> cost = $item -> cost ;
//$product->qty = $item->qty;
}
2014-02-01 21:01:32 +01:00
$product -> save ();
}
$invoiceItem = InvoiceItem :: createNew ();
$invoiceItem -> product_id = isset ( $product ) ? $product -> id : null ;
2014-10-19 20:32:10 +02:00
$invoiceItem -> product_key = Utils :: processVariables ( trim ( $item -> product_key ));
$invoiceItem -> notes = Utils :: processVariables ( trim ( $item -> notes ));
2014-02-01 21:01:32 +01:00
$invoiceItem -> cost = Utils :: parseFloat ( $item -> cost );
$invoiceItem -> qty = Utils :: parseFloat ( $item -> qty );
$invoiceItem -> tax_rate = 0 ;
if ( isset ( $item -> tax_rate ) && Utils :: parseFloat ( $item -> tax_rate ) > 0 )
{
$invoiceItem -> tax_rate = Utils :: parseFloat ( $item -> tax_rate );
$invoiceItem -> tax_name = trim ( $item -> tax_name );
}
$invoice -> invoice_items () -> save ( $invoiceItem );
}
2014-01-08 21:09:47 +01:00
if ( $data [ 'set_default_terms' ])
{
$account = \Auth :: user () -> account ;
$account -> invoice_terms = $invoice -> terms ;
$account -> save ();
}
2013-12-25 22:34:42 +01:00
return $invoice ;
}
2014-01-12 19:55:33 +01:00
2014-05-25 16:48:00 +02:00
public function cloneInvoice ( $invoice , $quotePublicId = null )
2014-05-20 23:40:09 +02:00
{
2014-05-25 16:25:58 +02:00
$invoice -> load ( 'invitations' , 'invoice_items' );
2014-05-25 16:48:00 +02:00
$clone = Invoice :: createNew ( $invoice );
2014-05-20 23:40:09 +02:00
$clone -> balance = $invoice -> amount ;
2014-10-19 18:44:20 +02:00
$clone -> invoice_number = $invoice -> account -> getNextInvoiceNumber ();
2014-05-20 23:40:09 +02:00
foreach ([
2014-05-22 20:29:29 +02:00
'client_id' ,
2014-05-20 23:40:09 +02:00
'discount' ,
'invoice_date' ,
'po_number' ,
'due_date' ,
'is_recurring' ,
'frequency_id' ,
'start_date' ,
'end_date' ,
'terms' ,
'public_notes' ,
'invoice_design_id' ,
'tax_name' ,
'tax_rate' ,
'amount' ,
2014-10-14 09:46:30 +02:00
'is_quote' ,
'custom_value1' ,
'custom_value2' ,
'custom_taxes1' ,
'custom_taxes2' ] as $field )
2014-05-20 23:40:09 +02:00
{
$clone -> $field = $invoice -> $field ;
}
2014-05-25 12:57:19 +02:00
if ( $quotePublicId )
2014-05-20 23:40:09 +02:00
{
$clone -> is_quote = false ;
2014-05-25 12:57:19 +02:00
$clone -> quote_id = $quotePublicId ;
2014-05-20 23:40:09 +02:00
}
2014-05-25 16:25:58 +02:00
2014-05-20 23:40:09 +02:00
$clone -> save ();
2014-05-25 12:57:19 +02:00
if ( $quotePublicId )
2014-05-20 23:40:09 +02:00
{
2014-05-25 12:57:19 +02:00
$invoice -> quote_invoice_id = $clone -> public_id ;
2014-05-20 23:40:09 +02:00
$invoice -> save ();
}
2014-05-25 16:25:58 +02:00
2014-05-20 23:40:09 +02:00
foreach ( $invoice -> invoice_items as $item )
{
2014-05-25 16:48:00 +02:00
$cloneItem = InvoiceItem :: createNew ( $invoice );
2014-05-20 23:40:09 +02:00
foreach ([
'product_id' ,
'product_key' ,
'notes' ,
'cost' ,
'qty' ,
'tax_name' ,
'tax_rate' ] as $field )
{
$cloneItem -> $field = $item -> $field ;
}
$clone -> invoice_items () -> save ( $cloneItem );
}
foreach ( $invoice -> invitations as $invitation )
{
2014-05-25 16:48:00 +02:00
$cloneInvitation = Invitation :: createNew ( $invoice );
2014-05-20 23:40:09 +02:00
$cloneInvitation -> contact_id = $invitation -> contact_id ;
$cloneInvitation -> invitation_key = str_random ( RANDOM_KEY_LENGTH );
$clone -> invitations () -> save ( $cloneInvitation );
}
return $clone ;
}
2014-10-14 21:04:48 +02:00
public function bulk ( $ids , $action , $statusId = false )
2014-01-12 19:55:33 +01:00
{
if ( ! $ids )
{
return 0 ;
}
2014-09-13 23:13:09 +02:00
$invoices = Invoice :: withTrashed () -> scope ( $ids ) -> get ();
2014-01-12 19:55:33 +01:00
foreach ( $invoices as $invoice )
{
2014-10-14 21:04:48 +02:00
if ( $action == 'mark' )
{
$invoice -> invoice_status_id = $statusId ;
$invoice -> save ();
}
else
{
if ( $action == 'delete' )
{
$invoice -> is_deleted = true ;
$invoice -> save ();
}
2014-01-12 19:55:33 +01:00
2014-10-14 21:04:48 +02:00
$invoice -> delete ();
}
2014-01-12 19:55:33 +01:00
}
return count ( $invoices );
}
2013-12-25 22:34:42 +01:00
}