Remove old payments
This commit is contained in:
parent
156b92f765
commit
2a6fd1152b
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Invoice\Actions;
|
||||
|
||||
use App\Invoice\BillDocument;
|
||||
use App\Invoice\BillKind;
|
||||
use App\Invoice\Models\Invoice;
|
||||
use App\Invoice\RememberDocument;
|
||||
use Illuminate\Http\Response;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Zoomyboy\Tex\BaseCompiler;
|
||||
use Zoomyboy\Tex\Tex;
|
||||
|
||||
class MassPostPdfAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle(): BaseCompiler|Response
|
||||
{
|
||||
$documents = [];
|
||||
|
||||
foreach (Invoice::whereNeedsBill()->where('via', BillKind::POST)->get() as $invoice) {
|
||||
$document = BillDocument::fromInvoice($invoice);
|
||||
$documents[] = $document;
|
||||
$invoice->sent($document);
|
||||
}
|
||||
|
||||
foreach (Invoice::whereNeedsRemember()->where('via', BillKind::POST)->get() as $invoice) {
|
||||
$document = RememberDocument::fromInvoice($invoice);
|
||||
$documents[] = $document;
|
||||
$invoice->sent($document);
|
||||
}
|
||||
|
||||
if (!count($documents)) {
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
return Tex::merge($documents);
|
||||
}
|
||||
}
|
|
@ -7,10 +7,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
|||
|
||||
class BillDocument extends InvoiceDocument
|
||||
{
|
||||
public function linkLabel(): string
|
||||
{
|
||||
return 'Rechnung erstellen';
|
||||
}
|
||||
|
||||
public function getSubject(): string
|
||||
{
|
||||
|
@ -21,40 +17,4 @@ class BillDocument extends InvoiceDocument
|
|||
{
|
||||
return 'tex.bill';
|
||||
}
|
||||
|
||||
public static function sendAllLabel(): string
|
||||
{
|
||||
return 'Rechnungen versenden';
|
||||
}
|
||||
|
||||
public function afterSingle(Payment $payment): void
|
||||
{
|
||||
$payment->update([
|
||||
'invoice_data' => $this->toArray(),
|
||||
'status_id' => 2,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HasMany<Payment> $query
|
||||
*
|
||||
* @return HasMany<Payment>
|
||||
*/
|
||||
public static function paymentsQuery(HasMany $query): HasMany
|
||||
{
|
||||
return $query->whereNeedsBill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Descriptions for sendpayment page.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public static function getDescription(): array
|
||||
{
|
||||
return [
|
||||
'Diese Funktion erstellt ein PDF mit allen noch nicht versendenden Rechnungen bei den Mitgliedern die Post als Versandweg haben.',
|
||||
'Die Rechnungen werden automatisch auf "Rechnung gestellt" aktualisiert.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,21 +14,6 @@ abstract class InvoiceDocument extends Document
|
|||
{
|
||||
abstract public function getSubject(): string;
|
||||
abstract public function view(): string;
|
||||
abstract public function afterSingle(Payment $payment): void;
|
||||
abstract public function linkLabel(): string;
|
||||
abstract public static function sendAllLabel(): string;
|
||||
|
||||
/**
|
||||
* @param HasMany<Payment> $query
|
||||
*
|
||||
* @return HasMany<Payment>
|
||||
*/
|
||||
abstract public static function paymentsQuery(HasMany $query): HasMany;
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
abstract public static function getDescription(): array;
|
||||
|
||||
public string $until;
|
||||
public string $filename;
|
||||
|
|
|
@ -91,10 +91,11 @@ class Invoice extends Model
|
|||
*/
|
||||
public function scopeWhereNeedsRemember(Builder $query): Builder
|
||||
{
|
||||
return $query->where('status', InvoiceStatus::SENT)->whereNotNull('sent_at')->where(function ($query) {
|
||||
return $query->orWhere('last_remembered_at', '<=', now()->subMonths(3))
|
||||
->orWhereNull('last_remembered_at');
|
||||
});
|
||||
return $query
|
||||
->where('status', InvoiceStatus::SENT)
|
||||
->whereNotNull('sent_at')
|
||||
->whereNotNull('last_remembered_at')
|
||||
->where('last_remembered_at', '<=', now()->subMonths(3));
|
||||
}
|
||||
|
||||
public function getMailRecipient(): stdClass
|
||||
|
@ -111,6 +112,7 @@ class Invoice extends Model
|
|||
$this->update([
|
||||
'sent_at' => now(),
|
||||
'status' => InvoiceStatus::SENT,
|
||||
'last_remembered_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Invoice\Queries;
|
||||
|
||||
use App\Invoice\BillKind;
|
||||
use App\Member\Member;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class BillKindQuery extends InvoiceMemberQuery
|
||||
{
|
||||
public function __construct(
|
||||
private BillKind $billKind
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Builder<Member>
|
||||
*/
|
||||
protected function getQuery(): Builder
|
||||
{
|
||||
return Member::where('bill_kind', $this->billKind);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Invoice\Queries;
|
||||
|
||||
use App\Invoice\InvoiceDocument;
|
||||
use App\Member\Member;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
abstract class InvoiceMemberQuery
|
||||
{
|
||||
/**
|
||||
* @param class-string<InvoiceDocument> $type
|
||||
*/
|
||||
public string $type;
|
||||
|
||||
/**
|
||||
* @return Builder<Member>
|
||||
*/
|
||||
abstract protected function getQuery(): Builder;
|
||||
|
||||
/**
|
||||
* @return Collection<(int|string), EloquentCollection<(int|string), Member>>
|
||||
*/
|
||||
public function getMembers(): Collection
|
||||
{
|
||||
return $this->get()->groupBy(
|
||||
fn ($member) => Str::slug(
|
||||
"{$member->lastname}{$member->address}{$member->zip}{$member->location}",
|
||||
),
|
||||
)->toBase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<InvoiceDocument> $type
|
||||
*/
|
||||
public function type(string $type): self
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EloquentCollection<int, Member>
|
||||
*/
|
||||
private function get(): EloquentCollection
|
||||
{
|
||||
return $this->getQuery()
|
||||
->with([
|
||||
'payments' => fn ($query) => $this->type::paymentsQuery($query)
|
||||
->orderByRaw('nr, member_id'),
|
||||
])
|
||||
->get()
|
||||
->filter(fn (Member $member) => $member->payments->count() > 0);
|
||||
}
|
||||
}
|
|
@ -7,10 +7,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
|||
|
||||
class RememberDocument extends InvoiceDocument
|
||||
{
|
||||
public function linkLabel(): string
|
||||
{
|
||||
return 'Erinnerung erstellen';
|
||||
}
|
||||
|
||||
public function getSubject(): string
|
||||
{
|
||||
|
@ -21,37 +17,4 @@ class RememberDocument extends InvoiceDocument
|
|||
{
|
||||
return 'tex.remember';
|
||||
}
|
||||
|
||||
public static function sendAllLabel(): string
|
||||
{
|
||||
return 'Erinnerungen versenden';
|
||||
}
|
||||
|
||||
public function afterSingle(Payment $payment): void
|
||||
{
|
||||
$payment->update(['last_remembered_at' => now()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HasMany<Payment> $query
|
||||
*
|
||||
* @return HasMany<Payment>
|
||||
*/
|
||||
public static function paymentsQuery(HasMany $query): HasMany
|
||||
{
|
||||
return $query->whereNeedsRemember();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Descriptions for sendpayment page.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public static function getDescription(): array
|
||||
{
|
||||
return [
|
||||
'Diese Funktion erstellt Erinnerungs-PDFs mit allen versendeten aber noch nich bezahlten Rechnungen bei den Mitgliedern die Post als Versandweg haben.',
|
||||
'Das zuletzt erinnerte Datum wird auf heute gesetzt.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ class InvoiceResource extends JsonResource
|
|||
'links' => [
|
||||
'mass-store' => route('invoice.mass-store'),
|
||||
'store' => route('invoice.store'),
|
||||
'masspdf' => route('invoice.masspdf'),
|
||||
],
|
||||
'vias' => BillKind::forSelect(),
|
||||
'statuses' => InvoiceStatus::forSelect(),
|
||||
|
|
|
@ -18,13 +18,14 @@ class MemberShowAction
|
|||
public function handle(Member $member): array
|
||||
{
|
||||
return [
|
||||
'data' => new MemberResource($member
|
||||
->load('memberships')
|
||||
->load('payments.subscription.children')
|
||||
->load('nationality')
|
||||
->load('region')
|
||||
->load('subscription')
|
||||
->load('courses.course')
|
||||
'data' => new MemberResource(
|
||||
$member
|
||||
->load('memberships')
|
||||
->load('invoicePositions.invoice')
|
||||
->load('nationality')
|
||||
->load('region')
|
||||
->load('subscription')
|
||||
->load('courses.course')
|
||||
),
|
||||
'meta' => MemberResource::meta(),
|
||||
];
|
||||
|
@ -33,7 +34,7 @@ class MemberShowAction
|
|||
public function asController(Member $member): Response
|
||||
{
|
||||
session()->put('menu', 'member');
|
||||
session()->put('title', 'Mitglied '.$member->fullname);
|
||||
session()->put('title', 'Mitglied ' . $member->fullname);
|
||||
|
||||
return Inertia::render('member/ShowView', $this->handle($member));
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ use App\Invoice\BillKind;
|
|||
use App\Invoice\Models\InvoicePosition;
|
||||
use App\Nami\HasNamiField;
|
||||
use App\Nationality;
|
||||
use App\Payment\Payment;
|
||||
use App\Payment\Subscription;
|
||||
use App\Pdf\Sender;
|
||||
use App\Region;
|
||||
|
@ -111,13 +110,6 @@ class Member extends Model implements Geolocatable
|
|||
$this->update(['version' => $version]);
|
||||
}
|
||||
|
||||
public function createPayment(array $attributes): void
|
||||
{
|
||||
$this->payments()->create(array_merge($attributes, [
|
||||
'last_remembered_at' => now(),
|
||||
]));
|
||||
}
|
||||
|
||||
// ----------------------------------- Getters -----------------------------------
|
||||
public function getFullnameAttribute(): string
|
||||
{
|
||||
|
@ -270,14 +262,6 @@ class Member extends Model implements Geolocatable
|
|||
return $this->hasMany(Membership::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasMany<Payment>
|
||||
*/
|
||||
public function payments(): HasMany
|
||||
{
|
||||
return $this->hasMany(Payment::class)->orderBy('nr');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasMany<Membership>
|
||||
*/
|
||||
|
@ -297,7 +281,6 @@ class Member extends Model implements Geolocatable
|
|||
public static function booted()
|
||||
{
|
||||
static::deleting(function (self $model): void {
|
||||
$model->payments->each->delete();
|
||||
$model->memberships->each->delete();
|
||||
$model->courses->each->delete();
|
||||
$model->invoicePositions->each(function ($position) {
|
||||
|
@ -327,11 +310,9 @@ class Member extends Model implements Geolocatable
|
|||
public function scopeWithPendingPayment(Builder $query): Builder
|
||||
{
|
||||
return $query->addSelect([
|
||||
'pending_payment' => Payment::selectRaw('SUM(subscription_children.amount)')
|
||||
->whereColumn('payments.member_id', 'members.id')
|
||||
->whereNeedsPayment()
|
||||
->join('subscriptions', 'subscriptions.id', 'payments.subscription_id')
|
||||
->join('subscription_children', 'subscriptions.id', 'subscription_children.parent_id'),
|
||||
'pending_payment' => InvoicePosition::selectRaw('SUM(price)')
|
||||
->whereColumn('invoice_positions.member_id', 'members.id')
|
||||
->whereHas('invoice', fn ($query) => $query->whereNeedsPayment())
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -352,8 +333,8 @@ class Member extends Model implements Geolocatable
|
|||
*/
|
||||
public function scopeWhereAusstand(Builder $query): Builder
|
||||
{
|
||||
return $query->whereHas('payments', function ($q) {
|
||||
return $q->whereHas('status', fn ($q) => $q->where('is_remember', true));
|
||||
return $query->whereHas('invoicePositions', function ($q) {
|
||||
return $q->whereHas('invoice', fn ($query) => $query->whereNeedsPayment());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -8,14 +8,13 @@ use App\Course\Models\Course;
|
|||
use App\Course\Resources\CourseMemberResource;
|
||||
use App\Gender;
|
||||
use App\Invoice\BillKind;
|
||||
use App\Invoice\Resources\InvoicePositionResource;
|
||||
use App\Lib\HasMeta;
|
||||
use App\Member\Data\NestedGroup;
|
||||
use App\Member\Resources\NationalityResource;
|
||||
use App\Member\Resources\RegionResource;
|
||||
use App\Membership\MembershipResource;
|
||||
use App\Nationality;
|
||||
use App\Payment\PaymentResource;
|
||||
use App\Payment\Status;
|
||||
use App\Payment\Subscription;
|
||||
use App\Payment\SubscriptionResource;
|
||||
use App\Region;
|
||||
|
@ -72,11 +71,11 @@ class MemberResource extends JsonResource
|
|||
'bill_kind_name' => optional($this->bill_kind)->value,
|
||||
'has_nami' => null !== $this->nami_id,
|
||||
'children_phone' => $this->children_phone,
|
||||
'payments' => PaymentResource::collection($this->whenLoaded('payments')),
|
||||
'pending_payment' => $this->pending_payment ? number_format($this->pending_payment / 100, 2, ',', '.') . ' €' : null,
|
||||
'age_group_icon' => $this->ageGroupMemberships->first()?->subactivity->slug,
|
||||
'courses' => CourseMemberResource::collection($this->whenLoaded('courses')),
|
||||
'memberships' => MembershipResource::collection($this->whenLoaded('memberships')),
|
||||
'invoicePositions' => InvoicePositionResource::collection($this->whenLoaded('invoicePositions')),
|
||||
'nationality' => new NationalityResource($this->whenLoaded('nationality')),
|
||||
'region' => new RegionResource($this->whenLoaded('region')),
|
||||
'full_address' => $this->fullAddress,
|
||||
|
@ -157,7 +156,6 @@ class MemberResource extends JsonResource
|
|||
'links' => [
|
||||
'index' => route('member.index'),
|
||||
'create' => route('member.create'),
|
||||
'sendpayment' => route('sendpayment.create'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment;
|
||||
|
||||
use App\Invoice\DocumentFactory;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ActionFactory
|
||||
{
|
||||
/**
|
||||
* @return Collection<int, array{link: array{href: string, label: mixed}, text: mixed}>
|
||||
*/
|
||||
public function allLinks(): Collection
|
||||
{
|
||||
return app(DocumentFactory::class)->getTypes()->map(function ($repo) {
|
||||
return [
|
||||
'link' => [
|
||||
'href' => route('sendpayment.pdf', ['type' => $repo]),
|
||||
'label' => $repo::sendAllLabel(),
|
||||
],
|
||||
'text' => $repo::getDescription(),
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment;
|
||||
|
||||
use App\Member\Member;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Payment extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*/
|
||||
public $fillable = ['member_id', 'invoice_data', 'subscription_id', 'nr', 'status_id', 'last_remembered_at'];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $casts = [
|
||||
'invoice_data' => 'json',
|
||||
'last_remembered_at' => 'date',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Member, self>
|
||||
*/
|
||||
public function member(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Member::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Subscription, self>
|
||||
*/
|
||||
public function subscription(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Subscription::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Status, self>
|
||||
*/
|
||||
public function status(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Status::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Builder<self> $query
|
||||
*
|
||||
* @return Builder<self>
|
||||
*/
|
||||
public function scopeWhereNeedsPayment(Builder $query): Builder
|
||||
{
|
||||
return $query->whereHas('status', function ($q) {
|
||||
return $q->needsPayment();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Builder<self> $query
|
||||
*
|
||||
* @return Builder<self>
|
||||
*/
|
||||
public function scopeWhereNeedsBill(Builder $query): Builder
|
||||
{
|
||||
return $query->whereHas('status', function ($q) {
|
||||
return $q->where('is_bill', true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Builder<self> $query
|
||||
*
|
||||
* @return Builder<self>
|
||||
*/
|
||||
public function scopeWhereNeedsRemember(Builder $query): Builder
|
||||
{
|
||||
return $query->whereHas('status', function ($q) {
|
||||
return $q->where('is_remember', true);
|
||||
})->where(fn ($query) => $query->whereNull('last_remembered_at')->orWhere('last_remembered_at', '<=', now()->subMonths(3)));
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment;
|
||||
|
||||
use App\Member\Member;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
* @mixin Payment
|
||||
*/
|
||||
class PaymentResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'subscription_id' => $this->subscription_id,
|
||||
'subscription' => new SubscriptionResource($this->whenLoaded('subscription')),
|
||||
'status_name' => $this->status->name,
|
||||
'status_id' => $this->status->id,
|
||||
'nr' => $this->nr,
|
||||
'id' => $this->id,
|
||||
'is_accepted' => $this->status->isAccepted(),
|
||||
'links' => [
|
||||
'show' => $this->invoice_data
|
||||
? route('payment.pdf', ['payment' => $this->getModel()])
|
||||
: null,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function memberMeta(Member $member): array
|
||||
{
|
||||
return [
|
||||
'statuses' => Status::forSelect(),
|
||||
'subscriptions' => Subscription::forSelect(),
|
||||
'default' => [
|
||||
'nr' => '',
|
||||
'subscription_id' => null,
|
||||
'status_id' => null
|
||||
],
|
||||
'links' => [
|
||||
'store' => route('member.payment.store', ['member' => $member]),
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Invoice\BillDocument;
|
||||
use App\Invoice\BillKind;
|
||||
use App\Invoice\DocumentFactory;
|
||||
use App\Invoice\Queries\BillKindQuery;
|
||||
use Illuminate\Contracts\Support\Responsable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response as InertiaResponse;
|
||||
use Zoomyboy\Tex\Tex;
|
||||
|
||||
class SendpaymentController extends Controller
|
||||
{
|
||||
public function create(): InertiaResponse
|
||||
{
|
||||
session()->put('menu', 'member');
|
||||
session()->put('title', 'Rechnungen versenden');
|
||||
|
||||
return Inertia::render('sendpayment/VForm', [
|
||||
'types' => app(ActionFactory::class)->allLinks(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response|Responsable
|
||||
*/
|
||||
public function send(Request $request)
|
||||
{
|
||||
$memberCollection = (new BillKindQuery(BillKind::POST))->type($request->type)->getMembers();
|
||||
|
||||
if ($memberCollection->isEmpty()) {
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
$documents = $memberCollection->map(function ($members) use ($request) {
|
||||
$document = $request->type::fromMembers($members);
|
||||
app(DocumentFactory::class)->afterSingle($document, $members);
|
||||
return $document;
|
||||
});
|
||||
|
||||
|
||||
return Tex::merge($documents->all());
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class Status extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public $fillable = ['name', 'is_bill', 'is_remember'];
|
||||
public $timestamps = false;
|
||||
public $casts = [
|
||||
'is_bill' => 'boolean',
|
||||
'is_remember' => 'boolean',
|
||||
];
|
||||
|
||||
public static function default(): int
|
||||
{
|
||||
return static::where('is_bill', true)->where('is_remember', true)->first()->id;
|
||||
}
|
||||
|
||||
public function isAccepted(): bool
|
||||
{
|
||||
return false === $this->is_bill && false === $this->is_remember;
|
||||
}
|
||||
|
||||
// ---------------------------------- Scopes -----------------------------------
|
||||
/**
|
||||
* @param Builder<self> $query
|
||||
* @return Builder<self>
|
||||
*/
|
||||
public function scopeNeedsPayment(Builder $query): Builder
|
||||
{
|
||||
return $query->where(function (Builder $query): Builder {
|
||||
return $query->where('is_bill', true)->orWhere('is_remember', true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{name: string, id: int}>
|
||||
*/
|
||||
public static function forSelect(): array
|
||||
{
|
||||
return static::select('name', 'id')->get()->toArray();
|
||||
}
|
||||
}
|
|
@ -8,10 +8,8 @@ use App\Group;
|
|||
use App\Invoice\BillKind;
|
||||
use App\Member\Member;
|
||||
use App\Nationality;
|
||||
use App\Payment\Payment;
|
||||
use App\Payment\Subscription;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @extends Factory<Member>
|
||||
|
@ -82,20 +80,6 @@ class MemberFactory extends Factory
|
|||
return $this->state(['nami_id' => $namiId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, callable> $payments
|
||||
*/
|
||||
public function withPayments(array $payments): self
|
||||
{
|
||||
return $this->afterCreating(function (Model $model) use ($payments): void {
|
||||
foreach ($payments as $paymentClosure) {
|
||||
$factory = Payment::factory()->for($model);
|
||||
$factory = call_user_func($paymentClosure, $factory);
|
||||
$factory->create();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function sameFamilyAs(Member $member): self
|
||||
{
|
||||
return $this->state([
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories\Payment;
|
||||
|
||||
use App\Fee;
|
||||
use App\Payment\Payment;
|
||||
use App\Payment\Status;
|
||||
use App\Payment\Subscription;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\RequestFactories\Child;
|
||||
|
||||
/**
|
||||
* @extends Factory<Payment>
|
||||
*/
|
||||
class PaymentFactory extends Factory
|
||||
{
|
||||
protected $model = Payment::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'nr' => $this->faker->year,
|
||||
'subscription_id' => Subscription::factory()->create()->id,
|
||||
'status_id' => Status::factory()->create()->id,
|
||||
'last_remembered_at' => now(),
|
||||
];
|
||||
}
|
||||
|
||||
public function notPaid(): self
|
||||
{
|
||||
return $this->for(Status::whereName('Nicht bezahlt')->first());
|
||||
}
|
||||
|
||||
public function pending(): self
|
||||
{
|
||||
return $this->for(Status::whereName('Rechnung gestellt')->first())->state(['last_remembered_at' => now()->subYears(2)]);;
|
||||
}
|
||||
|
||||
public function paid(): self
|
||||
{
|
||||
return $this->for(Status::whereName('Rechnung beglichen')->first());
|
||||
}
|
||||
|
||||
public function nr(string $nr): self
|
||||
{
|
||||
return $this->state(['nr' => $nr]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, Child> $children
|
||||
* @param array<string, mixed> $state
|
||||
*/
|
||||
public function subscription(string $name, array $children, array $state = []): self
|
||||
{
|
||||
return $this->for(
|
||||
Subscription::factory()->state(['name' => $name])->for(Fee::factory())->children($children)->state($state)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories\Payment;
|
||||
|
||||
use App\Payment\Status;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<Status>
|
||||
*/
|
||||
class StatusFactory extends Factory
|
||||
{
|
||||
public $model = Status::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->sentence,
|
||||
'is_bill' => $this->faker->boolean,
|
||||
'is_remember' => $this->faker->boolean,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -21,10 +21,6 @@ class CreatePaymentsTable extends Migration
|
|||
$table->boolean('is_remember');
|
||||
});
|
||||
|
||||
Status::create(['name' => 'Nicht bezahlt', 'is_bill' => true, 'is_remember' => true]);
|
||||
Status::create(['name' => 'Rechnung gestellt', 'is_bill' => false, 'is_remember' => true]);
|
||||
Status::create(['name' => 'Rechnung beglichen', 'is_bill' => false, 'is_remember' => false]);
|
||||
|
||||
Schema::create('payments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nr');
|
||||
|
|
|
@ -92,6 +92,8 @@ services:
|
|||
|
||||
socketi:
|
||||
image: quay.io/soketi/soketi:89604f268623cf799573178a7ba56b7491416bde-16-debian
|
||||
ports:
|
||||
- "6001:6001"
|
||||
environment:
|
||||
SOKETI_DEFAULT_APP_ID: adremaid
|
||||
SOKETI_DEFAULT_APP_KEY: adremakey
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit bbab104f7e00c059ffffa115f6b769e2333e137a
|
||||
Subproject commit b4dbd7d3125aca2c16ca9f99ec81c12a46a18e3b
|
15
phpstan.neon
15
phpstan.neon
|
@ -116,11 +116,6 @@ parameters:
|
|||
count: 1
|
||||
path: app/Member/Member.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Member\\\\Member\\:\\:createPayment\\(\\) has parameter \\$attributes with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: app/Member/Member.php
|
||||
|
||||
-
|
||||
message: "#^Unsafe usage of new static\\(\\)\\.$#"
|
||||
count: 1
|
||||
|
@ -136,11 +131,6 @@ parameters:
|
|||
count: 1
|
||||
path: app/Membership/MembershipResource.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Payment\\\\PaymentResource\\:\\:toArray\\(\\) return type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: app/Payment/PaymentResource.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Payment\\\\SubscriptionResource\\:\\:toArray\\(\\) return type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
|
@ -181,11 +171,6 @@ parameters:
|
|||
count: 1
|
||||
path: database/factories/NationalityFactory.php
|
||||
|
||||
-
|
||||
message: "#^Method Database\\\\Factories\\\\Payment\\\\StatusFactory\\:\\:definition\\(\\) return type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: database/factories/Payment/StatusFactory.php
|
||||
|
||||
-
|
||||
message: "#^Call to an undefined method Phake\\\\Proxies\\\\StubberProxy.*#"
|
||||
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
<page-toolbar-button color="primary" icon="plus" @click="create">Rechnung anlegen</page-toolbar-button>
|
||||
<page-toolbar-button color="primary" icon="plus" @click="massstore = { year: '' }">Massenrechnung
|
||||
anlegen</page-toolbar-button>
|
||||
<page-toolbar-button :href="meta.links.masspdf" color="primary" icon="plus">Post-Briefe
|
||||
abrufen</page-toolbar-button>
|
||||
</template>
|
||||
|
||||
<ui-popup v-if="massstore !== null" heading="Massenrechnung anlegen" @close="massstore = null">
|
||||
<form @submit.prevent="sendMassstore">
|
||||
<section class="grid grid-cols-2 gap-3 mt-6">
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
anlegen</page-toolbar-button>
|
||||
<page-toolbar-button v-if="hasModule('bill')" :href="meta.links.allpayment" color="primary"
|
||||
icon="invoice">Rechnungen erstellen</page-toolbar-button>
|
||||
<page-toolbar-button v-if="hasModule('bill')" :href="meta.links.sendpayment" color="info"
|
||||
icon="envelope">Rechnungen versenden</page-toolbar-button>
|
||||
</template>
|
||||
<ui-popup v-if="deleting !== null" heading="Mitglied löschen?" @close="deleting.reject()">
|
||||
<div>
|
||||
|
|
|
@ -30,6 +30,7 @@ use App\Invoice\Actions\DisplayRememberpdfAction;
|
|||
use App\Invoice\Actions\InvoiceDestroyAction;
|
||||
use App\Invoice\Actions\InvoiceIndexAction;
|
||||
use App\Invoice\Actions\InvoiceUpdateAction;
|
||||
use App\Invoice\Actions\MassPostPdfAction;
|
||||
use App\Invoice\Actions\MassStoreAction;
|
||||
use App\Invoice\Actions\PaymentPositionIndexAction;
|
||||
use App\Maildispatcher\Actions\CreateAction;
|
||||
|
@ -52,7 +53,6 @@ use App\Membership\Actions\MembershipDestroyAction;
|
|||
use App\Membership\Actions\MembershipStoreAction;
|
||||
use App\Membership\Actions\MembershipUpdateAction;
|
||||
use App\Membership\Actions\StoreForGroupAction;
|
||||
use App\Payment\SendpaymentController;
|
||||
use App\Payment\SubscriptionController;
|
||||
|
||||
Route::group(['namespace' => 'App\\Http\\Controllers'], function (): void {
|
||||
|
@ -70,8 +70,6 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
|||
Route::delete('/member/{member}', MemberDeleteAction::class);
|
||||
Route::get('/member/{member}', MemberShowAction::class)->name('member.show');
|
||||
Route::resource('subscription', SubscriptionController::class);
|
||||
Route::get('/sendpayment', [SendpaymentController::class, 'create'])->name('sendpayment.create');
|
||||
Route::get('/sendpayment/pdf', [SendpaymentController::class, 'send'])->name('sendpayment.pdf');
|
||||
Route::get('/member/{member}/efz', ShowEfzDocumentAction::class)->name('efz');
|
||||
Route::get('/member/{member}/resync', MemberResyncAction::class)->name('member.resync');
|
||||
Route::get('member-export', ExportAction::class)->name('member-export');
|
||||
|
@ -114,6 +112,7 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
|||
Route::delete('/invoice/{invoice}', InvoiceDestroyAction::class)->name('invoice.destroy');
|
||||
Route::get('/invoice/{invoice}/pdf', DisplayPdfAction::class)->name('invoice.pdf');
|
||||
Route::get('/invoice/{invoice}/rememberpdf', DisplayRememberpdfAction::class)->name('invoice.rememberpdf');
|
||||
Route::get('/invoice/masspdf', MassPostPdfAction::class)->name('invoice.masspdf');
|
||||
|
||||
|
||||
// ----------------------------- invoice-position ------------------------------
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
namespace Tests\EndToEnd;
|
||||
|
||||
use App\Group;
|
||||
use App\Invoice\Models\Invoice;
|
||||
use App\Invoice\Models\InvoicePosition;
|
||||
use App\Member\Member;
|
||||
use App\Payment\Payment;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
|
@ -57,9 +59,7 @@ class MemberIndexTest extends TestCase
|
|||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
$group = Group::factory()->create();
|
||||
Member::factory()->defaults()->for($group)
|
||||
->has(Payment::factory()->notPaid()->subscription('tollerbeitrag', [
|
||||
new Child('a', 5400),
|
||||
]))
|
||||
->has(InvoicePosition::factory()->for(Invoice::factory()))
|
||||
->create(['firstname' => '::firstname::']);
|
||||
Member::factory()->defaults()->for($group)->create(['firstname' => '::firstname::']);
|
||||
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Invoice;
|
||||
|
||||
use App\Invoice\BillDocument;
|
||||
use App\Invoice\BillKind;
|
||||
use App\Invoice\Invoice;
|
||||
use App\Invoice\Queries\BillKindQuery;
|
||||
use App\Invoice\Queries\InvoiceMemberQuery;
|
||||
use App\Member\Member;
|
||||
use App\Payment\Payment;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class BillRememberDocumentTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItCreatesOneFileForFamilyMembers(): void
|
||||
{
|
||||
Member::factory()
|
||||
->defaults()
|
||||
->postBillKind()
|
||||
->state(['firstname' => 'Max1', 'lastname' => '::lastname::', 'address' => '::address::', 'zip' => '12345', 'location' => '::location::'])
|
||||
->has(Payment::factory()->notPaid()->nr('nr1'))
|
||||
->create();
|
||||
Member::factory()
|
||||
->defaults()
|
||||
->postBillKind()
|
||||
->state(['firstname' => 'Max2', 'lastname' => '::lastname::', 'address' => '::address::', 'zip' => '12345', 'location' => '::location::'])
|
||||
->has(Payment::factory()->notPaid()->nr('nr2'))
|
||||
->create();
|
||||
|
||||
$this->assertCount(2, $this->query(BillDocument::class)->getMembers()->first());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<Invoice> $type
|
||||
*/
|
||||
private function query(string $type): InvoiceMemberQuery
|
||||
{
|
||||
return (new BillKindQuery(BillKind::POST))->type($type);
|
||||
}
|
||||
}
|
|
@ -48,6 +48,7 @@ class InvoiceIndexActionTest extends TestCase
|
|||
->assertInertiaPath('data.data.0.links.destroy', route('invoice.destroy', ['invoice' => $invoice]))
|
||||
->assertInertiaPath('data.meta.links.mass-store', route('invoice.mass-store'))
|
||||
->assertInertiaPath('data.meta.links.store', route('invoice.store'))
|
||||
->assertInertiaPath('data.meta.links.masspdf', route('invoice.masspdf'))
|
||||
->assertInertiaPath('data.meta.vias.0', ['id' => 'E-Mail', 'name' => 'E-Mail'])
|
||||
->assertInertiaPath('data.meta.statuses.0', ['id' => 'Neu', 'name' => 'Neu'])
|
||||
->assertInertiaPath('data.meta.members.0', ['id' => $member->id, 'name' => 'Aaaa Aaab'])
|
||||
|
|
|
@ -52,7 +52,7 @@ class InvoiceSendActionTest extends TestCase
|
|||
->has(InvoicePosition::factory()->withMember(), 'positions')
|
||||
->via(BillKind::EMAIL)
|
||||
->status(InvoiceStatus::SENT)
|
||||
->create(['sent_at' => now()->subMonths(6), 'mail_email' => 'max@muster.de']);
|
||||
->create(['sent_at' => now()->subMonths(6), 'mail_email' => 'max@muster.de', 'last_remembered_at' => now()->subMonths(6)]);
|
||||
|
||||
InvoiceSendAction::run();
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Invoice;
|
||||
|
||||
use App\Invoice\BillKind;
|
||||
use App\Invoice\Enums\InvoiceStatus;
|
||||
use App\Invoice\Models\Invoice;
|
||||
use App\Invoice\Models\InvoicePosition;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class MassPostPdfActionTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItDoesntDisplayPdfWhenNoMembersFound(): void
|
||||
{
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
|
||||
$this->get(route('invoice.masspdf'))->assertStatus(204);
|
||||
}
|
||||
|
||||
public function testItDoesntDisplayPdfWhenAllInvoicesPaid(): void
|
||||
{
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
|
||||
Invoice::factory()->has(InvoicePosition::factory()->withMember(), 'positions')->via(BillKind::POST)->status(InvoiceStatus::PAID)->create();
|
||||
|
||||
$this->get(route('invoice.masspdf'))->assertStatus(204);
|
||||
}
|
||||
|
||||
public function testItDoesntDisplayEmailBills(): void
|
||||
{
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
|
||||
Invoice::factory()->has(InvoicePosition::factory()->withMember(), 'positions')->via(BillKind::EMAIL)->create();
|
||||
|
||||
$this->get(route('invoice.masspdf'))->assertStatus(204);
|
||||
}
|
||||
|
||||
public function testItMergesRememberAndBill(): void
|
||||
{
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
$invoice1 = Invoice::factory()->has(InvoicePosition::factory()->withMember(), 'positions')->status(InvoiceStatus::NEW)
|
||||
->via(BillKind::POST)
|
||||
->create();
|
||||
$invoice2 = Invoice::factory()->has(InvoicePosition::factory()->withMember(), 'positions')->status(InvoiceStatus::SENT)
|
||||
->via(BillKind::POST)
|
||||
->create(['sent_at' => now()->subMonths(10), 'last_remembered_at' => now()->subMonths(4)]);
|
||||
|
||||
$this->get(route('invoice.masspdf'))->assertPdfPageCount(2);
|
||||
|
||||
$this->assertEquals(InvoiceStatus::SENT, $invoice1->fresh()->status);
|
||||
$this->assertEquals(now()->format('Y-m-d'), $invoice1->fresh()->last_remembered_at->format('Y-m-d'));
|
||||
$this->assertEquals(now()->format('Y-m-d'), $invoice1->fresh()->sent_at->format('Y-m-d'));
|
||||
|
||||
$this->assertEquals(InvoiceStatus::SENT, $invoice2->fresh()->status);
|
||||
$this->assertEquals(now()->format('Y-m-d'), $invoice2->fresh()->last_remembered_at->format('Y-m-d'));
|
||||
$this->assertEquals(now()->subMonths(10)->format('Y-m-d'), $invoice2->fresh()->sent_at->format('Y-m-d'));
|
||||
}
|
||||
}
|
|
@ -4,6 +4,9 @@ namespace Tests\Feature\Member;
|
|||
|
||||
use App\Activity;
|
||||
use App\Group;
|
||||
use App\Invoice\Enums\InvoiceStatus;
|
||||
use App\Invoice\Models\Invoice;
|
||||
use App\Invoice\Models\InvoicePosition;
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use App\Payment\Payment;
|
||||
|
@ -175,7 +178,7 @@ class IndexTest extends TestCase
|
|||
{
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
Member::factory()
|
||||
->has(Payment::factory()->notPaid()->subscription('Free', [new Child('b', 50)]))
|
||||
->has(InvoicePosition::factory()->for(Invoice::factory()->status(InvoiceStatus::NEW)))
|
||||
->defaults()->create();
|
||||
Member::factory()->defaults()->create();
|
||||
Member::factory()->defaults()->create();
|
||||
|
|
|
@ -7,6 +7,8 @@ use App\Course\Models\CourseMember;
|
|||
use App\Fee;
|
||||
use App\Gender;
|
||||
use App\Group;
|
||||
use App\Invoice\Models\Invoice;
|
||||
use App\Invoice\Models\InvoicePosition;
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use App\Nationality;
|
||||
|
@ -32,10 +34,7 @@ class ShowTest extends TestCase
|
|||
->defaults()
|
||||
->for(Group::factory()->name('Stamm Beispiel'))
|
||||
->has(Membership::factory()->promise(now())->in('€ LeiterIn', 5, 'Jungpfadfinder', 88)->from('2022-11-19'))
|
||||
->has(Payment::factory()->notPaid()->nr('2019')->subscription('Free', [
|
||||
new Child('uu', 1000),
|
||||
new Child('a', 50),
|
||||
]))
|
||||
->has(InvoicePosition::factory()->for(Invoice::factory())->price(1050)->description('uu'))
|
||||
->for(Gender::factory()->name('Männlich'))
|
||||
->for(Region::factory()->name('NRW'))
|
||||
->postBillKind()
|
||||
|
@ -130,15 +129,12 @@ class ShowTest extends TestCase
|
|||
],
|
||||
], $response, 'data.courses.0');
|
||||
$this->assertInertiaHas([
|
||||
'subscription' => [
|
||||
'name' => 'Free',
|
||||
'id' => $member->payments->first()->subscription->id,
|
||||
'amount' => 1050,
|
||||
'amount_human' => '10,50 €',
|
||||
],
|
||||
'status_name' => 'Nicht bezahlt',
|
||||
'nr' => '2019',
|
||||
], $response, 'data.payments.0');
|
||||
'description' => 'uu',
|
||||
'price_human' => '10,50 €',
|
||||
'invoice' => [
|
||||
'status' => 'Neu',
|
||||
]
|
||||
], $response, 'data.invoicePositions.0');
|
||||
}
|
||||
|
||||
public function testItShowsMinimalSingleMember(): void
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Sendpayment;
|
||||
|
||||
use App\Invoice\BillDocument;
|
||||
use App\Invoice\BillKind;
|
||||
use App\Invoice\InvoiceSettings;
|
||||
use App\Invoice\Queries\BillKindQuery;
|
||||
use App\Invoice\RememberDocument;
|
||||
use App\Member\Member;
|
||||
use App\Payment\Payment;
|
||||
use App\Payment\Status;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\RequestFactories\Child;
|
||||
use Tests\RequestFactories\InvoiceSettingsFake;
|
||||
use Tests\TestCase;
|
||||
use Zoomyboy\Tex\Tex;
|
||||
|
||||
class SendpaymentTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItCanViewSendpaymentPage(): void
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
$this->login()->loginNami();
|
||||
|
||||
$response = $this->get(route('sendpayment.create'));
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertInertiaHas('Rechnungen versenden', $response, 'types.0.link.label');
|
||||
$href = $this->inertia($response, 'types.0.link.href');
|
||||
$this->assertStringContainsString('BillDocument', $href);
|
||||
}
|
||||
|
||||
public function testItDownloadsPdfOfAllMembersForBill(): void
|
||||
{
|
||||
InvoiceSettings::fake(InvoiceSettingsFake::new()->create());
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
Member::factory()->defaults()->postBillKind()->count(3)
|
||||
->has(Payment::factory()->notPaid()->subscription('tollerbeitrag', [new Child('a', 5400)]))
|
||||
->create();
|
||||
|
||||
$response = $this->call('GET', route('sendpayment.pdf'), ['type' => 'App\\Invoice\\BillDocument']);
|
||||
$response->assertOk();
|
||||
$this->assertPdfPageCount(3, $response->getFile());
|
||||
}
|
||||
|
||||
public function testItDownloadsPdfOfAllMembersForRemember(): void
|
||||
{
|
||||
InvoiceSettings::fake(InvoiceSettingsFake::new()->create());
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
Member::factory()->defaults()->postBillKind()->count(3)
|
||||
->has(Payment::factory()->pending()->subscription('tollerbeitrag', [new Child('a', 5400)]))
|
||||
->create();
|
||||
|
||||
$response = $this->call('GET', route('sendpayment.pdf'), ['type' => 'App\\Invoice\\RememberDocument']);
|
||||
$response->assertOk();
|
||||
$this->assertPdfPageCount(3, $response->getFile());
|
||||
}
|
||||
|
||||
public function testItCanCreatePdfPayments(): void
|
||||
{
|
||||
InvoiceSettings::fake(InvoiceSettingsFake::new()->create());
|
||||
Tex::spy();
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
$members = Member::factory()
|
||||
->defaults()
|
||||
->has(Payment::factory()->notPaid()->nr('1997')->subscription('tollerbeitrag', [new Child('a', 5400)]))
|
||||
->has(Payment::factory()->paid()->nr('1998')->subscription('bezahltdesc', [new Child('b', 5800)]))
|
||||
->postBillKind()
|
||||
->count(3)
|
||||
->create();
|
||||
$member = $members->first();
|
||||
|
||||
$this->call('GET', route('sendpayment.pdf'), ['type' => 'App\\Invoice\\BillDocument']);
|
||||
$this->assertEquals(Status::firstWhere('name', 'Rechnung gestellt')->id, $member->payments->firstWhere('nr', '1997')->status_id);
|
||||
$this->assertEquals(Status::firstWhere('name', 'Rechnung beglichen')->id, $member->payments->firstWhere('nr', '1998')->status_id);
|
||||
Tex::assertCompiled(
|
||||
BillDocument::class,
|
||||
fn ($document) => $document->hasAllContent(['1997', 'tollerbeitrag', '54.00'])
|
||||
&& $document->missesAllContent(['1998', 'bezahltdesc', '58.00'])
|
||||
);
|
||||
|
||||
$member->payments->firstWhere('nr', '1997')->update(['status_id' => Status::firstWhere('name', 'Nicht bezahlt')->id]);
|
||||
$invoice = BillDocument::fromMembers((new BillKindQuery(BillKind::POST))->type(BillDocument::class)->getMembers()->first());
|
||||
$this->assertEquals(
|
||||
BillDocument::from($member->payments->firstWhere('nr', '1997')->invoice_data)->renderBody(),
|
||||
$invoice->renderBody()
|
||||
);
|
||||
}
|
||||
|
||||
public function testItCanCreatePdfPaymentsForRemember(): void
|
||||
{
|
||||
InvoiceSettings::fake(InvoiceSettingsFake::new()->create());
|
||||
Tex::spy();
|
||||
$this->withoutExceptionHandling()->login()->loginNami();
|
||||
$member = Member::factory()
|
||||
->defaults()
|
||||
->has(Payment::factory()->pending()->nr('1997')->subscription('tollerbeitrag', [new Child('a', 5400)]))
|
||||
->postBillKind()
|
||||
->create();
|
||||
|
||||
$this->call('GET', route('sendpayment.pdf'), ['type' => 'App\\Invoice\\RememberDocument']);
|
||||
Tex::assertCompiled(
|
||||
RememberDocument::class,
|
||||
fn ($document) => $document->hasAllContent(['1997', 'tollerbeitrag', '54.00'])
|
||||
);
|
||||
$this->assertNull($member->payments()->first()->invoice_data);
|
||||
$this->assertEquals(now()->format('Y-m-d'), $member->payments->first()->last_remembered_at->format('Y-m-d'));
|
||||
}
|
||||
|
||||
public function testItDoesntCreatePdfsWhenUserHasEmail(): void
|
||||
{
|
||||
Tex::spy();
|
||||
$this->withoutExceptionHandling();
|
||||
$this->login()->loginNami();
|
||||
Member::factory()
|
||||
->defaults()
|
||||
->has(Payment::factory()->notPaid()->nr('1997')->subscription('tollerbeitrag', [new Child('u', 5400)]))
|
||||
->emailBillKind()
|
||||
->create();
|
||||
|
||||
$response = $this->call('GET', route('sendpayment.pdf'), ['type' => 'App\\Invoice\\BillDocument']);
|
||||
|
||||
$response->assertStatus(204);
|
||||
Tex::assertNotCompiled(BillDocument::class);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue