Compare commits
95 Commits
62be191e9a
...
a6050b1e07
Author | SHA1 | Date |
---|---|---|
|
a6050b1e07 | |
|
c085de4761 | |
|
5d6add1976 | |
|
f461c37ccc | |
|
cd4bd971eb | |
|
8024fb7e58 | |
|
52eae62ce9 | |
|
fe4c414f1b | |
|
bd86f523b2 | |
|
90dac2b377 | |
|
7dfa269ff7 | |
|
89c8ce3ac1 | |
|
0b1ec69bf1 | |
|
0e0a7a9a1b | |
|
a33b67eae3 | |
|
24490afbc0 | |
|
c01e5fa39c | |
|
e57e908d39 | |
|
6d9d3dc793 | |
|
86b77945bf | |
|
faaefb90a4 | |
|
6aeab2fd93 | |
|
ae4a9616b4 | |
|
cb86306557 | |
|
84b0509d31 | |
|
d004cdcd7d | |
|
397ff52e35 | |
|
6cd896d7c9 | |
|
835ced7291 | |
|
fba9bfe5d5 | |
|
662a4dc720 | |
|
1ac0cae405 | |
|
ed207df4cf | |
|
513b832813 | |
|
f42ebdfcbb | |
|
6b49aa4f81 | |
|
3664739c86 | |
|
371a70c007 | |
|
a18fb18074 | |
|
5f7d1402bb | |
|
b64d9994ed | |
|
f99f97b5ae | |
|
a3f70fa10a | |
|
f46ffced8d | |
|
92156616da | |
|
318300ca88 | |
|
71d7189826 | |
|
98572ffdea | |
|
791e22eaa5 | |
|
660b012e1c | |
|
ac0b86cb08 | |
|
fb2292f8e4 | |
|
f9240270af | |
|
ae4b2aef31 | |
|
46b82922f7 | |
|
4b618be3b6 | |
|
71725c5045 | |
|
283c627a9c | |
|
32a53b4e77 | |
|
5f2e78fce7 | |
|
51741cd6b3 | |
|
603ec6bddc | |
|
429f7f70f5 | |
|
8132a771f4 | |
|
aa87d507ab | |
|
79784b70de | |
|
141dbdfd9b | |
|
4cbb390211 | |
|
bc21447f30 | |
|
c0451786d5 | |
|
6590ca14e5 | |
|
fe134d86ca | |
|
ceec787f2e | |
|
077e79192a | |
|
21f769b0de | |
|
4216d37bff | |
|
7d167e212a | |
|
0948a8172d | |
|
4496529ef0 | |
|
28469c7b40 | |
|
82c56f25fb | |
|
9450faac7d | |
|
ded5da6eb3 | |
|
09d49edad2 | |
|
212d83e6dc | |
|
270a4674fa | |
|
d1d6564805 | |
|
17e4fe5f82 | |
|
b2f3e4f1fd | |
|
376c1ceb9b | |
|
056b8f9ed6 | |
|
011e414848 | |
|
5e64797277 | |
|
2e8dc96665 | |
|
b1dcdeb579 |
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -1,5 +1,21 @@
|
|||
# Letzte Änderungen
|
||||
|
||||
### 1.12.6
|
||||
|
||||
- Fix: Beiträge von Familienmitgliedern splitten
|
||||
|
||||
### 1.12.5
|
||||
|
||||
- Fix: Synchronisieren von bestehenden Beiträgen aus NaMi
|
||||
|
||||
### 1.12.4
|
||||
|
||||
- Filter Mitglieder nach Verhaltenskodex
|
||||
|
||||
### 1.12.3
|
||||
|
||||
- Volltextsuche für Rechnungen
|
||||
|
||||
### 1.12.2
|
||||
|
||||
- Zuschussliste Gallier
|
||||
|
|
|
@ -22,7 +22,8 @@ class InsertMemberAction
|
|||
{
|
||||
$region = Region::firstWhere('nami_id', $member->regionId ?: -1);
|
||||
|
||||
return Member::updateOrCreate(['nami_id' => $member->id], [
|
||||
|
||||
$payload = [
|
||||
'firstname' => $member->firstname,
|
||||
'lastname' => $member->lastname,
|
||||
'joined_at' => $member->joinedAt,
|
||||
|
@ -51,7 +52,16 @@ class InsertMemberAction
|
|||
'mitgliedsnr' => $member->memberId,
|
||||
'version' => $member->version,
|
||||
'keepdata' => $member->keepdata,
|
||||
]);
|
||||
];
|
||||
|
||||
// Dont update subscription if fee id of existing member's subscription is already the same
|
||||
if ($existing = Member::nami($member->id)) {
|
||||
if ($existing->subscription && $existing->subscription->fee->nami_id === $member->feeId) {
|
||||
$payload['subscription_id'] = $existing->subscription->id;
|
||||
}
|
||||
}
|
||||
|
||||
return Member::updateOrCreate(['nami_id' => $member->id], $payload);
|
||||
}
|
||||
|
||||
public function getSubscription(NamiMember $member): ?Subscription
|
||||
|
|
|
@ -49,7 +49,6 @@ class Invoice extends Model
|
|||
*/
|
||||
public static function createForMember(Member $member, Collection $members, int $year, Subscription $subscription = null): self
|
||||
{
|
||||
$subscription = $subscription ?: $member->subscription;
|
||||
$invoice = new self([
|
||||
'to' => [
|
||||
'name' => 'Familie ' . $member->lastname,
|
||||
|
@ -66,7 +65,8 @@ class Invoice extends Model
|
|||
|
||||
$positions = collect([]);
|
||||
foreach ($members as $member) {
|
||||
foreach ($subscription->children as $child) {
|
||||
$memberSubscription = $subscription ?: $member->subscription;
|
||||
foreach ($memberSubscription->children as $child) {
|
||||
$positions->push([
|
||||
'description' => str($child->name)->replace('{name}', $member->firstname . ' ' . $member->lastname)->replace('{year}', (string) $year),
|
||||
'price' => $child->amount,
|
||||
|
|
|
@ -46,6 +46,8 @@ class FilterScope extends ScoutFilter
|
|||
public array $exclude = [],
|
||||
public ?bool $hasFullAddress = null,
|
||||
public ?bool $hasBirthday = null,
|
||||
public ?bool $hasSvk = null,
|
||||
public ?bool $hasVk = null,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -85,6 +87,12 @@ class FilterScope extends ScoutFilter
|
|||
if ($this->hasBirthday === true) {
|
||||
$filter->push('birthday IS NOT NULL');
|
||||
}
|
||||
if ($this->hasSvk !== null) {
|
||||
$filter->push('has_svk = ' . ($this->hasSvk ? 'true' : 'false'));
|
||||
}
|
||||
if ($this->hasVk !== null) {
|
||||
$filter->push('has_vk = ' . ($this->hasVk ? 'true' : 'false'));
|
||||
}
|
||||
if ($this->ausstand === true) {
|
||||
$filter->push('ausstand > 0');
|
||||
}
|
||||
|
|
|
@ -544,6 +544,8 @@ class Member extends Model implements Geolocatable
|
|||
'bill_kind' => $this->bill_kind?->value,
|
||||
'group_id' => $this->group->id,
|
||||
'group_name' => $this->group->inner_name ?: $this->group->name,
|
||||
'has_vk' => $this->has_vk,
|
||||
'has_svk' => $this->has_svk,
|
||||
'links' => [
|
||||
'show' => route('member.show', ['member' => $this], false),
|
||||
'edit' => route('member.edit', ['member' => $this], false),
|
||||
|
|
|
@ -163,6 +163,10 @@ class MemberResource extends JsonResource
|
|||
'activity_ids' => [],
|
||||
'subactivity_ids' => []
|
||||
],
|
||||
'boolean_filter' => [
|
||||
['id' => true, 'name' => 'Ja'],
|
||||
['id' => false, 'name' => 'Nein'],
|
||||
],
|
||||
'default' => [
|
||||
'gender_id' => null,
|
||||
'salutation' => '',
|
||||
|
|
|
@ -138,7 +138,7 @@ return [
|
|||
'key' => env('MEILI_MASTER_KEY', null),
|
||||
'index-settings' => [
|
||||
Member::class => [
|
||||
'filterableAttributes' => ['address', 'birthday', 'ausstand', 'bill_kind', 'group_id', 'memberships', 'id'],
|
||||
'filterableAttributes' => ['address', 'birthday', 'ausstand', 'bill_kind', 'group_id', 'memberships', 'has_vk', 'has_svk', 'id'],
|
||||
'searchableAttributes' => ['fullname', 'address'],
|
||||
'sortableAttributes' => ['lastname', 'firstname'],
|
||||
'displayedAttributes' => ['age_group_icon', 'group_name', 'links', 'is_leader', 'lastname', 'firstname', 'fullname', 'address', 'ausstand', 'birthday', 'id', 'memberships', 'bill_kind', 'group_id'],
|
||||
|
|
|
@ -37,6 +37,8 @@ class MemberFactory extends Factory
|
|||
'email' => $this->faker->safeEmail(),
|
||||
'recertified_at' => null,
|
||||
'keepdata' => false,
|
||||
'has_svk' => $this->faker->boolean(),
|
||||
'has_vk' => $this->faker->boolean(),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,24 @@
|
|||
size="sm"
|
||||
@update:model-value="setFilter('ausstand', $event)"
|
||||
></f-switch>
|
||||
<f-select
|
||||
id="has_vk"
|
||||
name="has_vk"
|
||||
:model-value="getFilter('has_vk')"
|
||||
label="Verhaltenskodex unterschrieben"
|
||||
size="sm"
|
||||
:options="meta.boolean_filter"
|
||||
@update:model-value="setFilter('has_vk', $event)"
|
||||
></f-select>
|
||||
<f-select
|
||||
id="has_svk"
|
||||
name="has_svk"
|
||||
:model-value="getFilter('has_svk')"
|
||||
label="SVK unterschrieben"
|
||||
size="sm"
|
||||
:options="meta.boolean_filter"
|
||||
@update:model-value="setFilter('has_svk', $event)"
|
||||
></f-select>
|
||||
<f-multipleselect
|
||||
id="group_ids"
|
||||
:options="meta.groups"
|
||||
|
|
|
@ -202,6 +202,30 @@ class MemberIndexTest extends EndToEndTestCase
|
|||
]])->assertInertiaCount('data.data', 1);
|
||||
}
|
||||
|
||||
public function testItFiltersForSvkPrevention(): void
|
||||
{
|
||||
Member::factory()->defaults()->create(['has_svk' => true]);
|
||||
Member::factory()->defaults()->create(['has_svk' => false]);
|
||||
Member::factory()->defaults()->create(['has_svk' => false]);
|
||||
|
||||
sleep(1);
|
||||
$this->callFilter('member.index', ['has_svk' => true])->assertInertiaCount('data.data', 1);
|
||||
$this->callFilter('member.index', ['has_svk' => false])->assertInertiaCount('data.data', 2);
|
||||
$this->callFilter('member.index', ['has_svk' => null])->assertInertiaCount('data.data', 3);
|
||||
}
|
||||
|
||||
public function testItFiltersForVkPrevention(): void
|
||||
{
|
||||
Member::factory()->defaults()->create(['has_vk' => true]);
|
||||
Member::factory()->defaults()->create(['has_vk' => false]);
|
||||
Member::factory()->defaults()->create(['has_vk' => false]);
|
||||
|
||||
sleep(1);
|
||||
$this->callFilter('member.index', ['has_vk' => true])->assertInertiaCount('data.data', 1);
|
||||
$this->callFilter('member.index', ['has_vk' => false])->assertInertiaCount('data.data', 2);
|
||||
$this->callFilter('member.index', ['has_vk' => null])->assertInertiaCount('data.data', 3);
|
||||
}
|
||||
|
||||
public function testGroupOfMembershipsFilterCanBeEmpty(): void
|
||||
{
|
||||
$mitglied = Activity::factory()->create();
|
||||
|
|
|
@ -90,8 +90,8 @@ class MassStoreActionTest extends TestCase
|
|||
|
||||
$this->assertDatabaseCount('invoices', 1);
|
||||
$this->assertDatabaseCount('invoice_positions', 2);
|
||||
$this->assertDatabaseHas('invoice_positions', ['description' => 'beitrag Max Muster']);
|
||||
$this->assertDatabaseHas('invoice_positions', ['description' => 'beitrag Jane Muster']);
|
||||
$this->assertDatabaseHas('invoice_positions', ['description' => 'beitrag Max Muster', 'price' => 4466]);
|
||||
$this->assertDatabaseHas('invoice_positions', ['description' => 'beitrag Jane Muster', 'price' => 4466]);
|
||||
}
|
||||
|
||||
public function testItSeparatesBillKinds(): void
|
||||
|
@ -105,4 +105,21 @@ class MassStoreActionTest extends TestCase
|
|||
$this->assertDatabaseCount('invoices', 2);
|
||||
$this->assertDatabaseCount('invoice_positions', 2);
|
||||
}
|
||||
|
||||
public function testItSeparatesSubscriptions(): void
|
||||
{
|
||||
$member1 = Member::factory()->defaults()->emailBillKind()
|
||||
->for(Subscription::factory()->forFee()->children([new Child('beitrag1 {name}', 4466)]))
|
||||
->create(['firstname' => 'Member1', 'lastname' => 'ln']);
|
||||
$member2 = Member::factory()->defaults()->sameFamilyAs($member1)->emailBillKind()
|
||||
->for(Subscription::factory()->forFee()->children([new Child('beitrag2 {name}', 4467)]))
|
||||
->create(['firstname' => 'Member2']);
|
||||
|
||||
$this->postJson(route('invoice.mass-store'), ['year' => now()->addYear()->year])->assertOk();
|
||||
$invoice = Invoice::first();
|
||||
|
||||
$this->assertDatabaseCount('invoice_positions', 2);
|
||||
$this->assertDatabaseHas('invoice_positions', ['invoice_id' => $invoice->id, 'member_id' => $member1->id, 'description' => 'beitrag1 Member1 ln', 'price' => 4466]);
|
||||
$this->assertDatabaseHas('invoice_positions', ['invoice_id' => $invoice->id, 'member_id' => $member2->id, 'description' => 'beitrag2 Member2 ln', 'price' => 4467]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use App\Country;
|
|||
use App\Fee;
|
||||
use App\Gender;
|
||||
use App\Group;
|
||||
use App\Member\Member;
|
||||
use App\Nationality;
|
||||
use App\Payment\Subscription;
|
||||
use App\Region;
|
||||
|
@ -142,3 +143,20 @@ it('testItPullsMemberWithNoSubscription', function () {
|
|||
'subscription_id' => null,
|
||||
]);
|
||||
});
|
||||
|
||||
it('doesnt set first subscription if fee matches', function () {
|
||||
$this->loginNami();
|
||||
Subscription::factory()->forFee(55)->create();
|
||||
$otherSubscription = Subscription::factory()->forFee(55)->create();
|
||||
$member = Member::factory()->defaults()->inNami(1001)->create(['subscription_id' => $otherSubscription->id]);
|
||||
app(MemberFake::class)->shows(1000, 1001, [
|
||||
'beitragsartId' => 55,
|
||||
]);
|
||||
|
||||
app(PullMemberAction::class)->handle(1000, 1001);
|
||||
|
||||
$this->assertDatabaseHas('members', [
|
||||
'subscription_id' => $otherSubscription->id,
|
||||
'id' => $member->id,
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -149,7 +149,7 @@ class ShowTest extends TestCase
|
|||
->for(Group::factory())
|
||||
->for(Nationality::factory()->name('deutsch'))
|
||||
->for(Subscription::factory()->forFee())
|
||||
->create(['firstname' => 'Max', 'lastname' => 'Muster']);
|
||||
->create(['firstname' => 'Max', 'lastname' => 'Muster', 'has_vk' => false, 'has_svk' => false]);
|
||||
|
||||
$response = $this->get("/member/{$member->id}");
|
||||
|
||||
|
|
Loading…
Reference in New Issue