2018-07-06 06:57:49 +00:00
< ? php
namespace App\Models ;
2024-07-05 06:38:31 +00:00
use Illuminate\Database\Eloquent\Builder ;
2021-06-30 04:00:41 +00:00
use Illuminate\Database\Eloquent\Factories\HasFactory ;
2018-07-06 06:57:49 +00:00
use Illuminate\Database\Eloquent\Model ;
2024-07-05 02:04:08 +00:00
use Illuminate\Support\Collection ;
use Illuminate\Support\Facades\DB ;
2021-06-29 06:36:34 +00:00
use Leenooks\Traits\ScopeActive ;
2018-07-06 06:57:49 +00:00
2021-06-29 06:36:34 +00:00
use App\Interfaces\IDs ;
2018-08-20 12:15:28 +00:00
2021-06-29 06:36:34 +00:00
/**
* Class Account
* Service Accounts
*
* Attributes for accounts :
2021-12-24 01:14:01 +00:00
* + lid : Local ID for account
* + sid : System ID for account
* + name : Account Name
* + taxes : Taxes Applicable to this account
2021-06-29 06:36:34 +00:00
*/
class Account extends Model implements IDs
2018-07-06 06:57:49 +00:00
{
2024-07-05 02:04:08 +00:00
use HasFactory , ScopeActive ;
2018-08-20 12:15:28 +00:00
2024-07-05 06:38:31 +00:00
/* STATIC */
public static function InvoicesDue ( Collection $invoices = NULL ) : Collection
{
return ( new self )
-> invoiceSummaryDue ( $invoices , TRUE )
-> get ();
}
2022-04-21 04:41:26 +00:00
/* INTERFACES */
public function getLIDAttribute () : string
{
return sprintf ( '%04s' , $this -> id );
}
public function getSIDAttribute () : string
{
return sprintf ( '%02s-%s' , $this -> site_id , $this -> getLIDAttribute ());
}
2018-07-17 04:10:40 +00:00
2021-06-29 06:36:34 +00:00
/* RELATIONS */
2024-07-05 02:04:08 +00:00
/**
* Charges assigned to this account
*
* @ return \Illuminate\Database\Eloquent\Relations\HasMany
*/
2021-10-01 04:59:04 +00:00
public function charges ()
{
return $this -> hasMany ( Charge :: class );
}
2018-07-13 04:53:44 +00:00
/**
2024-07-05 02:04:08 +00:00
* Country this account belongs to
2018-07-13 04:53:44 +00:00
*/
public function country ()
{
return $this -> belongsTo ( Country :: class );
}
2019-06-12 06:25:15 +00:00
public function external ()
{
return $this -> belongsToMany ( External\Integrations :: class , 'external_account' , NULL , 'external_integration_id' );
}
2021-12-24 01:14:01 +00:00
public function group ()
{
return $this -> hasOneThrough ( Group :: class , AccountGroup :: class , 'account_id' , 'id' , 'id' , 'group_id' );
}
2023-05-09 10:28:51 +00:00
/**
2024-07-05 02:04:08 +00:00
* Invoices created for this account
*
2023-05-09 10:28:51 +00:00
* @ todo This needs to be optimised , to only return outstanding invoices and invoices for a specific age ( eg : 2 years worth )
*/
2019-06-11 02:36:58 +00:00
public function invoices ()
{
2023-05-09 10:28:51 +00:00
return $this -> hasMany ( Invoice :: class )
-> with ([ 'items.taxes' , 'paymentitems.payment' ]);
2019-06-11 02:36:58 +00:00
}
2024-07-05 02:04:08 +00:00
/**
* Relation to only return active invoices
*
* @ todo Only return active invoice_items
*/
public function invoices_active ()
2018-07-13 04:53:44 +00:00
{
2024-07-05 02:04:08 +00:00
return $this -> invoices ()
-> active ();
2018-07-13 04:53:44 +00:00
}
2024-07-05 02:04:08 +00:00
/**
* Payments received and assigned to this account
*/
2019-06-07 06:54:27 +00:00
public function payments ()
{
2023-05-09 10:28:51 +00:00
return $this -> hasMany ( Payment :: class )
-> with ([ 'items' ]);
2019-06-07 06:54:27 +00:00
}
2024-07-05 02:04:08 +00:00
/**
* Relation to only return active payments
*
* @ todo Only return active payment_items
*/
public function payments_active ()
{
return $this -> payments ()
-> active ();
}
2022-08-19 10:12:08 +00:00
public function providers ()
{
2023-05-10 07:37:43 +00:00
return $this -> belongsToMany ( ProviderOauth :: class , 'account__provider' )
-> where ( 'account__provider.site_id' , $this -> site_id )
2022-08-19 10:12:08 +00:00
-> withPivot ( 'ref' , 'synctoken' , 'created_at' , 'updated_at' );
}
2024-07-05 02:04:08 +00:00
/**
* Services assigned to this account
*/
public function services ()
2018-08-08 23:33:51 +00:00
{
2024-07-05 02:04:08 +00:00
return $this -> hasMany ( Service :: class )
2024-07-05 06:38:31 +00:00
-> with ([ 'product.translate' , 'product.type.supplied' ]);
2018-08-08 23:33:51 +00:00
}
2024-07-05 02:04:08 +00:00
/**
* Relation to only return active services
*/
public function services_active ()
2022-03-05 00:05:35 +00:00
{
2024-07-05 02:04:08 +00:00
return $this -> services ()
-> active ();
2022-03-05 00:05:35 +00:00
}
2021-12-24 01:14:01 +00:00
public function taxes ()
{
2024-07-05 02:04:08 +00:00
return $this -> hasMany ( Tax :: class , 'country_id' , 'country_id' )
-> select ([ 'id' , 'zone' , 'rate' , 'country_id' ]);
2021-12-24 01:14:01 +00:00
}
2024-07-05 02:04:08 +00:00
/**
* User that owns this account
*/
2018-07-13 04:53:44 +00:00
public function user ()
{
2021-06-29 03:18:52 +00:00
return $this -> belongsTo ( User :: class );
2018-07-13 04:53:44 +00:00
}
2018-07-17 04:10:40 +00:00
2021-06-29 06:36:34 +00:00
/* SCOPES */
2020-04-01 12:35:06 +00:00
2019-06-21 06:21:48 +00:00
/**
* Search for a record
*
2019-06-29 00:14:12 +00:00
* @ param $query
* @ param string $term
2021-07-23 07:25:26 +00:00
* @ return mixed
2019-06-21 06:21:48 +00:00
*/
public function scopeSearch ( $query , string $term )
{
// Build our where clause
2021-07-07 07:45:16 +00:00
if ( is_numeric ( $term )) {
2019-06-21 06:21:48 +00:00
$query -> where ( 'id' , 'like' , '%' . $term . '%' );
} else {
2021-07-07 07:45:16 +00:00
$query -> where ( 'company' , 'like' , '%' . $term . '%' )
-> orWhere ( 'address1' , 'like' , '%' . $term . '%' )
-> orWhere ( 'address2' , 'like' , '%' . $term . '%' )
-> orWhere ( 'city' , 'like' , '%' . $term . '%' );
2019-06-21 06:21:48 +00:00
}
return $query ;
}
2021-06-29 06:36:34 +00:00
/* ATTRIBUTES */
2019-06-21 06:21:48 +00:00
2021-07-01 23:12:34 +00:00
/**
* Get the address for the account
*
* @ return array
2024-07-05 02:04:08 +00:00
* @ todo Change this to return a collection
2021-07-01 23:12:34 +00:00
*/
public function getAddressAttribute () : array
{
2024-07-05 02:04:08 +00:00
return collect ([
'address1' => $this -> address1 ,
'address2' => $this -> address2 ,
'location' => sprintf ( '%s %s %s' ,
$this -> city . (( $this -> state || $this -> zip ) ? ',' : '' ),
$this -> state ,
$this -> zip )
])
-> filter ()
-> values ()
-> toArray ();
2022-07-29 07:45:17 +00:00
}
2021-06-29 06:36:34 +00:00
/**
2022-04-21 04:41:26 +00:00
* Return the account name
2021-06-29 06:36:34 +00:00
*
2024-07-05 02:04:08 +00:00
* @ return string
2021-06-29 06:36:34 +00:00
*/
2022-04-21 04:41:26 +00:00
public function getNameAttribute () : string
2019-06-07 06:54:27 +00:00
{
2022-04-21 06:25:29 +00:00
return $this -> company ? : ( $this -> user_id ? $this -> user -> getSurFirstNameAttribute () : 'LID:' . $this -> id );
2018-08-08 23:33:51 +00:00
}
2022-06-12 01:21:20 +00:00
/**
* Return the type of account this is - if it has a company name , then its a business account .
*
* @ return string
*/
2024-07-05 02:04:08 +00:00
public function getTypeAttribute () : string
2019-06-12 06:25:15 +00:00
{
return $this -> company ? 'Business' : 'Private' ;
}
2022-04-22 00:36:41 +00:00
/* METHODS */
2019-06-11 02:36:58 +00:00
/**
* Get the due invoices on an account
*
* @ return mixed
2024-07-05 02:04:08 +00:00
* @ deprecated use invoiceSummary -> filter ( _balance > 0 )
2019-06-11 02:36:58 +00:00
*/
public function dueInvoices ()
{
return $this -> invoices -> filter ( function ( $item ) {
return $item -> active AND $item -> due > 0 ;
});
}
2023-05-05 05:48:24 +00:00
2024-07-05 02:04:08 +00:00
/**
* List of invoices ( summary ) for this account
*
* @ param Collection | NULL $invoices
* @ return Collection
*/
2024-07-05 06:38:31 +00:00
public function invoiceSummary ( Collection $invoices = NULL , bool $all = FALSE ) : Builder
2024-07-05 02:04:08 +00:00
{
return ( new Invoice )
-> select ([
2024-07-05 06:38:31 +00:00
'invoices.account_id' ,
'invoices.id as id' ,
2024-07-05 02:04:08 +00:00
DB :: raw ( 'SUM(item) AS _item' ),
DB :: raw ( 'SUM(tax) AS _tax' ),
DB :: raw ( 'SUM(payments) AS _payment' ),
DB :: raw ( 'SUM(discount) AS _discount' ),
DB :: raw ( 'SUM(item_total) AS _item_total' ),
DB :: raw ( 'SUM(payment_fees) AS _payment_fee' ),
2024-07-05 13:36:28 +00:00
DB :: raw ( 'ROUND(CAST(SUM(item_total)-SUM(COALESCE(discount,0))-COALESCE(invoices.discount_amt,0) AS NUMERIC),2) AS _total' ),
DB :: raw ( 'ROUND(CAST(SUM(item_total)-SUM(COALESCE(discount,0))-COALESCE(invoices.discount_amt,0)-SUM(payments) AS NUMERIC),2) AS _balance' ),
2024-07-05 06:38:31 +00:00
'invoices.due_at' ,
'invoices.created_at' ,
2024-07-05 02:04:08 +00:00
])
-> from (
( new Payment )
-> select ([
'invoice_id' ,
DB :: raw ( '0 as item' ),
DB :: raw ( '0 as tax' ),
DB :: raw ( '0 as discount' ),
DB :: raw ( '0 as item_total' ),
DB :: raw ( 'SUM(amount) AS payments' ),
DB :: raw ( 'SUM(fees_amt) AS payment_fees' ),
])
-> join ( 'payment_items' ,[ 'payment_items.payment_id' => 'payments.id' ])
-> where ( 'payments.active' , TRUE )
-> where ( 'payment_items.active' , TRUE )
-> groupBy ([ 'payment_items.invoice_id' ])
-> union (
( new InvoiceItem )
-> select ([
'invoice_id' ,
DB :: raw ( 'ROUND(CAST(SUM(quantity*price_base) AS NUMERIC),2) AS item' ),
DB :: raw ( 'ROUND(CAST(SUM(amount) AS NUMERIC),2) AS tax' ),
DB :: raw ( 'SUM(COALESCE(invoice_items.discount_amt,0)) AS discount' ),
DB :: raw ( 'ROUND(CAST(SUM(ROUND(CAST(quantity*price_base AS NUMERIC),2))+SUM(ROUND(CAST(amount AS NUMERIC),2))-SUM(COALESCE(invoice_items.discount_amt,0)) AS NUMERIC),2) AS item_total' ),
DB :: raw ( '0 as payments' ),
DB :: raw ( '0 as payment_fees' ),
])
-> leftjoin ( 'invoice_item_taxes' ,[ 'invoice_item_taxes.invoice_item_id' => 'invoice_items.id' ])
-> rightjoin ( 'invoices' ,[ 'invoices.id' => 'invoice_items.invoice_id' ])
-> where ( 'invoice_items.active' , TRUE )
-> where ( 'invoices.active' , TRUE )
-> groupBy ([ 'invoice_items.invoice_id' ]),
), 'p' )
-> join ( 'invoices' ,[ 'invoices.id' => 'invoice_id' ])
2024-07-05 06:38:31 +00:00
-> when (( $all === FALSE ), fn ( $query ) => $query -> where ( 'invoices.account_id' , $this -> id ))
-> orderBy ( 'due_at' )
-> groupBy ([ 'invoices.account_id' , 'invoices.id' , 'invoices.created_at' , 'invoices.due_at' , 'invoices.discount_amt' ])
-> with ([ 'account' ]);
}
public function invoiceSummaryDue ( Collection $invoices = NULL , bool $all = FALSE ) : Builder
{
return $this -> invoiceSummary ( $invoices , $all )
-> havingRaw ( 'ROUND(CAST(SUM(item_total)-SUM(COALESCE(discount,0))+COALESCE(invoices.discount_amt,0)-SUM(payments) AS NUMERIC),2) > 0' );
}
public function invoiceSummaryPast ( Collection $invoices = NULL , bool $all = FALSE ) : Builder
{
return $this -> invoiceSummary ( $invoices , $all )
-> join ( 'payment_items' ,[ 'payment_items.invoice_id' => 'invoices.id' ])
-> join ( 'payments' ,[ 'payments.id' => 'payment_items.payment_id' ])
-> addSelect ( DB :: raw ( 'max(paid_at) as _paid_at' ))
-> havingRaw ( 'ROUND(CAST(SUM(item_total)-SUM(COALESCE(discount,0))+COALESCE(invoices.discount_amt,0)-SUM(payments) AS NUMERIC),2) <= 0' );
2024-07-05 02:04:08 +00:00
}
2023-05-05 05:48:24 +00:00
/**
* Return the taxed value of a value
*
* @ param float $value
* @ return float
*/
public function taxed ( float $value ) : float
{
return Tax :: calc ( $value , $this -> taxes );
}
2018-07-06 06:57:49 +00:00
}