2020-04-12 00:26:44 +02:00
< ? php
2020-06-02 23:45:25 +02:00
namespace App\Member ;
2020-04-12 00:26:44 +02:00
2021-07-15 21:20:57 +02:00
use App\Activity ;
2021-04-11 18:17:40 +02:00
use App\Bill\BillKind ;
2021-07-15 21:20:57 +02:00
use App\Confession ;
use App\Country ;
2021-11-20 00:48:42 +01:00
use App\Course\Models\CourseMember ;
2021-06-13 11:33:50 +02:00
use App\Group ;
2021-07-15 21:20:57 +02:00
use App\Nationality ;
2021-07-04 16:56:07 +02:00
use App\Payment\Payment ;
2021-07-15 21:20:57 +02:00
use App\Payment\Subscription ;
2022-10-28 12:01:04 +02:00
use App\Pdf\Sender ;
2021-07-15 21:20:57 +02:00
use App\Region ;
2022-03-06 02:57:39 +01:00
use App\Setting\NamiSettings ;
2021-07-15 21:20:57 +02:00
use App\Subactivity ;
2022-10-07 22:41:43 +02:00
use Carbon\Carbon ;
2022-10-06 20:57:38 +02:00
use Cviebrock\EloquentSluggable\Sluggable ;
2021-07-15 20:59:06 +02:00
use Illuminate\Database\Eloquent\Builder ;
2021-07-15 21:20:57 +02:00
use Illuminate\Database\Eloquent\Factories\HasFactory ;
use Illuminate\Database\Eloquent\Model ;
use Illuminate\Database\Eloquent\Relations\BelongsTo ;
2021-07-06 02:25:16 +02:00
use Illuminate\Database\Eloquent\Relations\HasMany ;
2021-07-15 21:20:57 +02:00
use Illuminate\Notifications\Notifiable ;
2022-10-06 20:57:38 +02:00
use Sabre\VObject\Component\VCard ;
2022-10-07 22:41:43 +02:00
use Sabre\VObject\Reader ;
2022-10-28 12:01:04 +02:00
use Spatie\LaravelData\Lazy ;
2021-07-06 02:25:16 +02:00
use Zoomyboy\LaravelNami\Api ;
2022-05-01 21:30:14 +02:00
use Zoomyboy\LaravelNami\Data\MembershipEntry ;
2020-04-12 00:26:44 +02:00
2022-01-02 12:32:57 +01:00
/**
2022-03-11 20:19:17 +01:00
* @ property string $subscription_name
* @ property int $pending_payment
* @ property bool $is_confirmed
* @ property string $age_group_icon
2022-09-06 01:25:04 +02:00
* @ property bool $is_leader
2022-01-02 12:32:57 +01:00
* @ property \Carbon\Carbon $try_created_at
*/
2020-04-12 00:26:44 +02:00
class Member extends Model
{
use Notifiable ;
2021-06-13 11:33:50 +02:00
use HasFactory ;
2022-10-06 20:57:38 +02:00
use Sluggable ;
2020-04-12 00:26:44 +02:00
2022-05-31 21:50:35 +02:00
public $guarded = [];
2020-04-12 00:26:44 +02:00
2022-10-07 14:47:35 +02:00
/**
* @ var array < int , string >
*/
2022-10-06 20:57:38 +02:00
public static array $namiFields = [ 'firstname' , 'lastname' , 'joined_at' , 'birthday' , 'send_newspaper' , 'address' , 'zip' , 'location' , 'nickname' , 'other_country' , 'further_address' , 'main_phone' , 'mobile_phone' , 'work_phone' , 'fax' , 'email' , 'email_parents' , 'gender_id' , 'confession_id' , 'region_id' , 'country_id' , 'fee_id' , 'nationality_id' , 'slug' ];
2022-05-31 22:08:52 +02:00
2022-10-07 14:47:35 +02:00
/**
* @ var array < int , string >
*/
2021-08-23 01:59:53 +02:00
public $dates = [ 'try_created_at' , 'joined_at' , 'birthday' ];
2020-04-12 00:26:44 +02:00
2022-10-07 14:47:35 +02:00
/**
* @ var array < string , string >
*/
2020-04-12 00:26:44 +02:00
public $casts = [
2021-07-04 21:47:20 +02:00
'pending_payment' => 'integer' ,
2021-04-10 02:11:13 +02:00
'send_newspaper' => 'boolean' ,
2020-04-12 00:26:44 +02:00
'gender_id' => 'integer' ,
'way_id' => 'integer' ,
'country_id' => 'integer' ,
'region_id' => 'integer' ,
'confession_id' => 'integer' ,
'nami_id' => 'integer' ,
2021-06-28 22:09:41 +02:00
'is_confirmed' => 'boolean' ,
2022-04-28 23:20:41 +02:00
'has_svk' => 'boolean' ,
'has_vk' => 'boolean' ,
'multiply_pv' => 'boolean' ,
'multiply_more_pv' => 'boolean' ,
2022-09-06 01:25:04 +02:00
'is_leader' => 'boolean' ,
2020-04-12 00:26:44 +02:00
];
2022-10-07 14:47:35 +02:00
/**
* @ return array < string , array { source : array < int , string > } >
*/
2022-10-06 20:57:38 +02:00
public function sluggable () : array
{
return [
'slug' => [ 'source' => [ 'firstname' , 'lastname' ]],
];
}
2022-03-11 20:19:17 +01:00
public function scopeSearch ( Builder $q , ? string $text ) : Builder
{
if ( is_null ( $text )) {
return $q ;
}
2020-06-02 23:45:25 +02:00
return $q -> where ( 'firstname' , 'LIKE' , '%' . $text . '%' )
-> orWhere ( 'lastname' , 'LIKE' , '%' . $text . '%' )
-> orWhere ( 'address' , 'LIKE' , '%' . $text . '%' )
-> orWhere ( 'zip' , 'LIKE' , '%' . $text . '%' )
2021-04-10 01:39:39 +02:00
-> orWhere ( 'location' , 'LIKE' , '%' . $text . '%' );
2020-04-12 00:26:44 +02:00
}
2021-10-29 19:34:50 +02:00
// ---------------------------------- Actions ----------------------------------
2022-03-06 02:57:39 +01:00
public function syncVersion () : void
2021-10-29 19:34:50 +02:00
{
2022-03-06 02:57:39 +01:00
$version = app ( NamiSettings :: class ) -> login () -> member ( $this -> group -> nami_id , $this -> nami_id )[ 'version' ];
2021-10-29 19:34:50 +02:00
$this -> update ([ 'version' => $version ]);
}
2020-06-02 23:45:25 +02:00
2021-10-30 00:50:03 +02:00
public function createPayment ( array $attributes ) : void
{
$this -> payments () -> create ( array_merge ( $attributes , [
'last_remembered_at' => now (),
]));
}
2022-05-17 01:37:07 +02:00
// ----------------------------------- Getters -----------------------------------
2022-03-11 20:19:17 +01:00
public function getFullnameAttribute () : string
{
2020-04-12 00:26:44 +02:00
return $this -> firstname . ' ' . $this -> lastname ;
}
2022-10-06 20:57:38 +02:00
public function getPreferredPhoneAttribute () : ? string
{
if ( $this -> mobile_phone ) {
return $this -> mobile_phone ;
}
if ( $this -> main_phone ) {
return $this -> main_phone ;
}
return null ;
}
2022-10-07 14:47:35 +02:00
public function getPreferredEmailAttribute () : ? string
{
if ( $this -> email ) {
return $this -> email ;
}
if ( $this -> email_parents ) {
return $this -> email_parents ;
}
return null ;
}
2022-10-06 20:57:38 +02:00
public function getEtagAttribute () : string
{
return $this -> updated_at -> timestamp . '_' . $this -> version ;
}
2022-08-23 23:49:19 +02:00
public function getFullAddressAttribute () : string
{
return $this -> address . ', ' . $this -> zip . ' ' . $this -> location ;
}
2022-03-20 16:33:56 +01:00
public function getEfzLink () : ? string
{
2022-08-23 23:49:19 +02:00
return $this -> isLeader ()
2022-03-20 16:33:56 +01:00
? route ( 'efz' , [ 'member' => $this ])
: null ;
}
2022-03-11 20:19:17 +01:00
public function getHasNamiAttribute () : bool
{
return null !== $this -> nami_id ;
2021-06-21 23:50:09 +02:00
}
2022-05-01 21:30:14 +02:00
/**
* @ return Collection < int , MembershipEntry >
*/
2022-03-11 20:19:17 +01:00
public function getNamiMemberships ( Api $api ) : array
{
2022-05-01 21:30:14 +02:00
return $api -> group ( $this -> group -> nami_id ) -> member ( $this -> nami_id ) -> memberships ();
2021-06-28 22:09:41 +02:00
}
2022-03-11 20:19:17 +01:00
public function getNamiFeeId () : ? int
{
2021-07-04 12:09:30 +02:00
if ( ! $this -> subscription ) {
return null ;
}
return $this -> subscription -> fee -> nami_id ;
}
2022-08-23 23:49:19 +02:00
public function isLeader () : bool
{
return $this -> memberships () -> whereHas ( 'activity' , fn ( Builder $query ) => $query -> where ( 'has_efz' , true )) -> exists ();
}
public function getAge () : int
{
return $this -> birthday -> diffInYears ( now ());
}
2022-05-17 01:37:07 +02:00
// ---------------------------------- Relations ----------------------------------
2021-07-15 21:20:57 +02:00
public function country () : BelongsTo
{
return $this -> belongsTo ( Country :: class );
2020-04-12 00:26:44 +02:00
}
2021-07-15 21:20:57 +02:00
public function gender () : BelongsTo
{
2020-04-12 00:26:44 +02:00
return $this -> belongsTo ( \App\Gender :: class );
}
2021-07-15 21:20:57 +02:00
public function region () : BelongsTo
{
2021-07-06 02:25:16 +02:00
return $this -> belongsTo ( Region :: class );
2020-04-12 00:26:44 +02:00
}
2021-07-15 21:20:57 +02:00
public function confession () : BelongsTo
{
2021-07-06 02:25:16 +02:00
return $this -> belongsTo ( Confession :: class );
2020-04-12 00:26:44 +02:00
}
2021-07-15 21:20:57 +02:00
public function payments () : HasMany
{
2021-07-04 16:56:07 +02:00
return $this -> hasMany ( Payment :: class ) -> orderBy ( 'nr' );
2020-04-12 00:26:44 +02:00
}
2021-07-15 21:20:57 +02:00
public function nationality () : BelongsTo
{
2021-06-13 11:33:50 +02:00
return $this -> belongsTo ( Nationality :: class );
2020-04-12 00:26:44 +02:00
}
2021-07-15 21:20:57 +02:00
public function memberships () : HasMany
{
2021-06-24 23:48:08 +02:00
return $this -> hasMany ( Membership :: class );
2020-04-12 00:26:44 +02:00
}
2021-07-15 21:20:57 +02:00
public function subscription () : BelongsTo
{
2021-07-04 12:09:30 +02:00
return $this -> belongsTo ( Subscription :: class );
2020-04-12 00:26:44 +02:00
}
2021-04-11 18:17:40 +02:00
2021-07-15 21:20:57 +02:00
public function billKind () : BelongsTo
{
2021-04-11 18:17:40 +02:00
return $this -> belongsTo ( BillKind :: class );
}
2021-07-15 21:20:57 +02:00
public function group () : BelongsTo
{
2021-06-13 11:33:50 +02:00
return $this -> belongsTo ( Group :: class );
}
2021-07-15 21:20:57 +02:00
public function firstActivity () : BelongsTo
{
2021-06-23 01:05:17 +02:00
return $this -> belongsTo ( Activity :: class , 'first_activity_id' );
}
2021-07-15 21:20:57 +02:00
public function firstSubActivity () : BelongsTo
{
2021-06-23 01:05:17 +02:00
return $this -> belongsTo ( Subactivity :: class , 'first_subactivity_id' );
}
2021-11-20 00:48:42 +01:00
public function courses () : HasMany
2021-11-18 01:54:27 +01:00
{
2021-11-20 00:48:42 +01:00
return $this -> hasMany ( CourseMember :: class );
2021-11-18 01:54:27 +01:00
}
2021-07-15 21:20:57 +02:00
public static function booted ()
{
2022-03-11 20:19:17 +01:00
static :: deleting ( function ( self $model ) : void {
2021-07-04 19:09:59 +02:00
$model -> payments -> each -> delete ();
});
2021-04-11 18:17:40 +02:00
}
2021-06-24 23:48:08 +02:00
2021-06-28 22:09:41 +02:00
// ---------------------------------- Scopes -----------------------------------
2022-08-11 23:19:52 +02:00
public function scopeOrdered ( Builder $q ) : Builder
{
return $q -> orderByRaw ( 'lastname, firstname' );
}
public function scopeSlangOrdered ( Builder $q ) : Builder
{
return $q -> orderByRaw ( 'firstname, lastname' );
}
2022-03-11 20:19:17 +01:00
public function scopeWithIsConfirmed ( Builder $q ) : Builder
{
2021-07-06 02:25:16 +02:00
return $q -> selectSub ( 'DATEDIFF(NOW(), IFNULL(confirmed_at, DATE_SUB(NOW(), INTERVAL 3 YEAR))) < 712' , 'is_confirmed' );
2021-06-24 23:48:08 +02:00
}
2022-03-11 20:19:17 +01:00
public function scopeWithSubscriptionName ( Builder $q ) : Builder
{
2021-07-04 18:29:21 +02:00
return $q -> addSelect ([
2022-03-11 20:19:17 +01:00
'subscription_name' => Subscription :: select ( 'name' ) -> whereColumn ( 'subscriptions.id' , 'members.subscription_id' ) -> limit ( 1 ),
2021-07-04 18:29:21 +02:00
]);
}
2022-03-11 20:19:17 +01:00
public function scopeWithPendingPayment ( Builder $q ) : Builder
{
2021-07-04 21:47:20 +02:00
return $q -> addSelect ([
'pending_payment' => Payment :: selectRaw ( 'SUM(subscriptions.amount)' )
-> whereColumn ( 'payments.member_id' , 'members.id' )
-> whereNeedsPayment ()
2022-03-11 20:19:17 +01:00
-> join ( 'subscriptions' , 'subscriptions.id' , 'payments.subscription_id' ),
2021-07-04 21:47:20 +02:00
]);
}
2022-03-11 20:19:17 +01:00
public function scopeWithAgeGroup ( Builder $q ) : Builder
{
2021-08-22 19:31:20 +02:00
return $q -> addSelect ([
'age_group_icon' => Subactivity :: select ( 'slug' )
-> join ( 'memberships' , 'memberships.subactivity_id' , 'subactivities.id' )
-> where ( 'subactivities.is_age_group' , true )
-> whereColumn ( 'memberships.member_id' , 'members.id' )
2022-03-11 20:19:17 +01:00
-> limit ( 1 ),
2021-08-22 19:31:20 +02:00
]);
}
2022-09-06 01:25:04 +02:00
public function scopeWithIsLeader ( Builder $q ) : Builder
{
return $q -> selectSub ( 'EXISTS(SELECT memberships.id FROM memberships INNER JOIN activities ON activities.id=memberships.activity_id INNER JOIN subactivities ON subactivities.id=memberships.subactivity_id WHERE members.id=memberships.member_id AND subactivities.is_age_group=1 AND activities.has_efz=1)' , 'is_leader' );
}
2022-03-11 20:19:17 +01:00
public function scopeWhereHasPendingPayment ( Builder $q ) : Builder
{
return $q -> whereHas ( 'payments' , function ( Builder $q ) : void {
2021-07-06 02:25:16 +02:00
$q -> whereNeedsPayment ();
2021-07-04 23:27:00 +02:00
});
}
2022-03-11 20:19:17 +01:00
public function scopeWhereAusstand ( Builder $q ) : Builder
{
return $q -> whereHas ( 'payments' , function ( $q ) {
2021-08-22 05:51:25 +02:00
return $q -> whereHas ( 'status' , fn ( $q ) => $q -> where ( 'is_remember' , true ));
});
}
2022-03-11 20:19:17 +01:00
public function scopePayable ( Builder $q ) : Builder
{
2021-07-06 02:25:16 +02:00
return $q -> where ( 'bill_kind_id' , '!=' , null ) -> where ( 'subscription_id' , '!=' , null );
2021-07-04 22:32:40 +02:00
}
2022-03-11 20:19:17 +01:00
public function scopeWhereNoPayment ( Builder $q , int $year ) : Builder
{
return $q -> whereDoesntHave ( 'payments' , function ( Builder $q ) use ( $year ) {
2021-07-06 02:25:16 +02:00
$q -> where ( 'nr' , '=' , $year );
2021-07-04 22:32:40 +02:00
});
}
2022-03-11 20:19:17 +01:00
public function scopeForDashboard ( Builder $q ) : Builder
{
2021-07-04 23:27:00 +02:00
return $q -> selectRaw ( 'SUM(id)' );
}
2021-08-22 05:51:25 +02:00
public function scopeFilter ( Builder $q , array $filter ) : Builder
{
2022-03-11 20:19:17 +01:00
if ( true === data_get ( $filter , 'ausstand' , false )) {
2021-08-22 05:51:25 +02:00
$q -> whereAusstand ();
}
if ( data_get ( $filter , 'bill_kind' , false )) {
$q -> where ( 'bill_kind_id' , $filter [ 'bill_kind' ]);
}
2021-08-23 00:46:41 +02:00
if ( data_get ( $filter , 'subactivity_id' , false ) || data_get ( $filter , 'activity_id' , false )) {
$q -> whereHas ( 'memberships' , function ( $q ) use ( $filter ) {
if ( data_get ( $filter , 'subactivity_id' , false )) {
$q -> where ( 'subactivity_id' , $filter [ 'subactivity_id' ]);
}
if ( data_get ( $filter , 'activity_id' , false )) {
$q -> where ( 'activity_id' , $filter [ 'activity_id' ]);
}
});
}
2021-08-22 05:51:25 +02:00
return $q ;
}
2021-08-23 01:59:53 +02:00
public function scopeEndingTries ( Builder $q ) : Builder
{
return $q -> whereHas ( 'memberships' , fn ( $q ) => $q
-> where ( 'created_at' , '<=' , now () -> subWeeks ( 7 ))
-> whereHas ( 'activity' , fn ( $q ) => $q -> where ( 'is_try' , true )))
-> addSelect ([
'try_created_at' => Membership :: select ( 'created_at' )
-> whereColumn ( 'memberships.member_id' , 'members.id' )
-> join ( 'activities' , 'activities.id' , 'memberships.activity_id' )
2022-03-11 20:19:17 +01:00
-> where ( 'activities.is_try' , true ),
2021-08-23 01:59:53 +02:00
]);
}
2022-10-06 20:57:38 +02:00
2022-10-07 22:41:43 +02:00
public static function fromVcard ( string $url , string $data ) : static
{
$settings = app ( NamiSettings :: class );
$card = Reader :: read ( $data );
[ $lastname , $firstname ] = $card -> N -> getParts ();
[ $deprecated1 , $deprecated2 , $address , $location , $region , $zip , $country ] = $card -> ADR -> getParts ();
return new static ([
'joined_at' => now (),
'send_newspaper' => false ,
'firstname' => $firstname ,
'lastname' => $lastname ,
'birthday' => Carbon :: createFromFormat ( 'Ymd' , $card -> BDAY -> getValue ()),
'slug' => pathinfo ( $url , PATHINFO_FILENAME ),
'address' => $address ,
'zip' => $zip ,
'location' => $location ,
'group_id' => $settings -> default_group_id ,
'nationality_id' => Nationality :: firstWhere ( 'name' , 'deutsch' ) -> id ,
'subscription_id' => Subscription :: firstWhere ( 'name' , 'Voll' ) -> id ,
]);
}
public function toVcard () : Vcard
2022-10-06 20:57:38 +02:00
{
$card = new VCard ([
2022-10-07 14:47:35 +02:00
'VERSION' => '3.0' ,
2022-10-06 20:57:38 +02:00
'FN' => $this -> fullname ,
'N' => [ $this -> lastname , $this -> firstname , '' , '' , '' ],
'BDAY' => $this -> birthday -> format ( 'Ymd' ),
2022-10-06 21:25:35 +02:00
'CATEGORIES' => 'Scoutrobot' ,
2022-10-07 22:41:43 +02:00
'UID' => $this -> slug ,
2022-10-06 20:57:38 +02:00
]);
2022-10-07 23:04:38 +02:00
if ( $this -> main_phone ) {
$card -> add ( 'TEL' , $this -> main_phone , [ 'type' => 'voice' ]);
2022-10-06 20:57:38 +02:00
}
if ( $this -> mobile_phone ) {
2022-10-07 23:04:38 +02:00
$card -> add ( 'TEL' , $this -> mobile_phone , [ 'type' => 'work' ]);
2022-10-06 20:57:38 +02:00
}
2022-10-06 21:25:35 +02:00
if ( $this -> children_phone ) {
2022-10-07 23:04:38 +02:00
$card -> add ( 'TEL' , $this -> children_phone , [ 'type' => 'cell' ]);
2022-10-06 21:25:35 +02:00
}
2022-10-06 20:57:38 +02:00
if ( $this -> email ) {
2022-10-07 23:04:38 +02:00
$card -> add ( 'EMAIL' , $this -> email , [ 'type' => 'internet' ]);
2022-10-06 20:57:38 +02:00
}
2022-10-07 14:47:35 +02:00
2022-10-06 20:57:38 +02:00
if ( $this -> email_parents ) {
2022-10-07 23:04:38 +02:00
$card -> add ( 'EMAIL' , $this -> email_parents , [ 'type' => 'aol' ]);
2022-10-06 20:57:38 +02:00
}
2022-10-06 21:25:35 +02:00
$card -> add ( 'ADR' , [
'' ,
'' ,
2022-10-06 20:57:38 +02:00
$this -> address ? : '' ,
$this -> location ? : '' ,
$this -> region ? -> name ? : '' ,
$this -> zip ? : '' ,
$this -> country ? -> name ? : '' ,
2022-10-06 21:25:35 +02:00
]);
2022-10-06 20:57:38 +02:00
return $card ;
}
2022-10-28 12:01:04 +02:00
public function toSender () : Sender
{
return Sender :: from ([
'name' => $this -> fullname ,
'address' => $this -> address ,
'zipLocation' => $this -> zip . ' ' . $this -> location ,
'mglnr' => Lazy :: create ( fn () => 'Mglnr.: ' . $this -> nami_id ),
]);
}
2020-04-12 00:26:44 +02:00
}