'/'.$name.'/'.implode('/', $parameters) ); $this->country = Country::create([ 'code' => 'DE', 'phone' => '49', 'en' => 'Germany', 'de' => 'Deutschland', 'es' => 'Alemania', 'fr' => 'Allemagne', 'it' => 'Germania', 'ru' => 'Германия', ]); $this->first = cpoConsultant(); $this->second = cpoConsultant(); $this->overview = app(CustomerPriorityOverviewService::class); }); function cpoConsultant(array $attributes = []): User { return User::forceCreate(array_merge([ 'email' => 'cpo-'.uniqid('', true).'@example.com', 'password' => Hash::make('secret'), 'lang' => 'de', 'active' => 1, ], $attributes)); } function cpoEntry(array $attributes = []): ShoppingUser { return ShoppingUser::create(array_merge([ 'auth_user_id' => null, 'member_id' => test()->first->id, 'number' => 100, 'billing_firstname' => 'Karola', 'billing_lastname' => 'Home', 'billing_address' => 'Weg 1', 'billing_zipcode' => '11111', 'billing_city' => 'Stadt', 'billing_email' => 'karola@example.com', 'billing_country_id' => test()->country->id, 'shipping_country_id' => test()->country->id, 'faker_mail' => false, ], $attributes)); } /** * Datatable endpoints read their parameters from the current request. */ function cpoDatatable(string $method): array { $request = Request::create('/datatable', 'GET', ['draw' => 1, 'start' => 0, 'length' => 50, 'search' => ['value' => '']]); app()->instance('request', $request); Facade::clearResolvedInstance('request'); return app(CustomerPriorityController::class)->{$method}()->getData(true); } // --- Kunde bei mehreren Beratern --- it('listet Kunden, deren E-Mail bei mehreren Beratern liegt, und markiert die älteste Zuordnung', function () { $oldest = cpoEntry(); cpoEntry(); $other = cpoEntry(['member_id' => $this->second->id, 'number' => 200]); cpoEntry(['billing_email' => 'eindeutig@example.com', 'number' => 300]); $conflicts = $this->overview->conflicts(); expect($conflicts)->toHaveCount(1); $row = $conflicts->first(); expect($row['email'])->toBe('karola@example.com') ->and($row['groups'])->toHaveCount(2) ->and($row['groups'][0]['member_id'])->toBe($this->first->id) ->and($row['groups'][0]['oldest'])->toBeTrue() ->and($row['groups'][0]['entries'])->toBe(2) ->and($row['groups'][0]['latest_id'])->not->toBe($oldest->id) ->and($row['groups'][1]['latest_id'])->toBe($other->id) ->and($row['groups'][1]['oldest'])->toBeFalse(); }); it('lässt offene Prüfungen, Beraterkonten und gelöschte Einträge aus der Konfliktliste', function () { cpoEntry(); cpoEntry(['member_id' => $this->second->id, 'number' => 200, 'is_like' => true]); cpoEntry(['billing_email' => 'berater@example.com']); cpoEntry(['billing_email' => 'berater@example.com', 'member_id' => $this->second->id, 'number' => 201]); cpoConsultant(['email' => 'berater@example.com']); cpoEntry(['billing_email' => 'weg@example.com']); cpoEntry(['billing_email' => 'weg@example.com', 'member_id' => $this->second->id, 'number' => 202]) ->forceFill(['gdpr_deleted_at' => now()])->save(); expect($this->overview->conflicts())->toBeEmpty(); }); // --- Offene Prüfungen --- it('zählt offene Prüfungen und abgelehnte E-Mail-Änderungen für das Menü', function () { $review = cpoEntry(['is_like' => true]); cpoEntry(['is_like' => true])->forceFill(['gdpr_deleted_at' => now()])->save(); cpoEntry(['number' => 101]); app(CustomerEmailChangeService::class)->reportConflict($review, 'fremd@example.com'); expect($this->overview->reviewsQuery()->pluck('id')->all())->toBe([$review->id]) ->and($this->overview->openCount())->toBe(2) ->and($this->overview->counts())->toBe(['reviews' => 1, 'conflicts' => 0, 'email_changes' => 1]); }); it('schließt einen Prüffall ohne Berater oder Nummer zu ändern', function () { $review = cpoEntry(['is_like' => true, 'member_id' => $this->second->id, 'number' => 555]); $review->setNotice('like', [99 => 100]); app(CustomerPriorityController::class)->keepAssignment($review->id); $review->refresh(); expect($review->is_like)->toBeFalse() ->and($review->getNotice('like'))->toBeFalse() ->and($review->member_id)->toBe($this->second->id) ->and($review->number)->toBe(555); }); // --- E-Mail-Änderungen --- it('zeigt abgelehnte und wartende E-Mail-Änderungen, bis sie erledigt oder verworfen sind', function () { $service = app(CustomerEmailChangeService::class); $customer = cpoEntry(); $blocked = $service->reportConflict($customer, 'fremd@example.com', $this->first->id); $pending = $service->request(cpoEntry(['number' => 101, 'billing_email' => 'b@example.com']), 'neu@example.com'); $service->changeDirectly(cpoEntry(['number' => 102, 'billing_email' => 'c@example.com']), 'admin@example.com'); expect($blocked->blocked_at)->not->toBeNull() ->and($this->overview->emailChangesQuery()->pluck('id')->sort()->values()->all())->toBe([$blocked->id, $pending->id]); $this->actingAs($this->first); $controller = app(CustomerPriorityController::class); $controller->resolveEmailChange($blocked->id, $service); $controller->discardEmailChange($pending->id, $service); expect($blocked->fresh()->resolved_by_user_id)->toBe($this->first->id) ->and($service->findConfirmable('egal'))->toBeNull() ->and($pending->fresh()->isConfirmable())->toBeFalse() ->and($this->overview->emailChangesQuery()->count())->toBe(0); }); // --- Datatables --- it('liefert die drei Listen als Datatable', function () { $review = cpoEntry(['is_like' => true, 'billing_email' => 'pruefung@example.com', 'number' => 400]); cpoEntry(); cpoEntry(['member_id' => $this->second->id, 'number' => 200]); app(CustomerEmailChangeService::class)->reportConflict($review, 'fremd@example.com'); $reviews = cpoDatatable('reviewsDatatable'); $conflicts = cpoDatatable('conflictsDatatable'); $changes = cpoDatatable('emailChangesDatatable'); expect($reviews['recordsTotal'])->toBe(1) ->and($reviews['data'][0]['customer'])->toContain('pruefung@example.com') ->and($reviews['data'][0]['action'])->toContain('shopping-user-is-like-member') ->and($conflicts['recordsTotal'])->toBe(1) ->and($conflicts['data'][0]['groups'])->toContain('älteste Zuordnung') ->and($conflicts['data'][0]['groups'])->toContain('shopping-user-change-member') ->and($changes['recordsTotal'])->toBe(1) ->and($changes['data'][0]['status'])->toContain('abgelehnt'); }); // --- Berater zuweisen aus der Übersicht --- it('führt nach "Berater zuweisen" zurück in die Übersicht und hängt alle Einträge des Kunden um', function () { cpoEntry(); $moved = cpoEntry(['member_id' => $this->second->id, 'number' => 200]); cpoEntry(['member_id' => $this->second->id, 'number' => 200]); $back = route('admin_customer_priority', ['conflicts']); $request = Request::create('/admin/customer/edit/'.$moved->id, 'POST', [ 'action' => 'shopping-user-change-member', 'id' => $moved->id, 'change_member_key' => config('mivita.edit_data_pass'), 'change_member_id' => $this->first->id, 'customer_set_member_for' => '1', 'back' => $back, ]); $request->setLaravelSession(app('session.store')); app()->instance('request', $request); Facade::clearResolvedInstance('request'); $response = app(AdminCustomerController::class)->store($moved->id); expect($response->getTargetUrl())->toEndWith('/admin_customer_priority/conflicts') ->and(ShoppingUser::where('number', '!=', 100)->where('member_id', $this->second->id)->count())->toBe(0) ->and($this->overview->conflicts())->toBeEmpty(); });