Skip to content

Commit d086ad1

Browse files
KhawarMehfooznielsdrost7
authored andcommitted
Store client CC email addresses as typed communications records instead of JSON on relations
1 parent 4c3060e commit d086ad1

6 files changed

Lines changed: 90 additions & 54 deletions

File tree

Modules/Clients/Database/Migrations/2026_07_13_000000_add_email_cc_to_relations_table.php

Lines changed: 0 additions & 21 deletions
This file was deleted.

Modules/Clients/Enums/CommunicationType.php

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66

77
enum CommunicationType: string implements LabeledEnum
88
{
9-
case EMAIL = 'email';
10-
case PHONE = 'phone';
11-
case FAX = 'fax';
12-
case MOBILE = 'mobile';
13-
case WHATSAPP = 'whatsapp';
9+
case EMAIL = 'email';
10+
case PHONE = 'phone';
11+
case FAX = 'fax';
12+
case MOBILE = 'mobile';
13+
case WHATSAPP = 'whatsapp';
14+
case INVOICE_CC = 'invoice_cc';
1415

1516
public static function values(): array
1617
{
@@ -20,22 +21,24 @@ public static function values(): array
2021
public function label(): string
2122
{
2223
return match ($this) {
23-
self::EMAIL => 'Email',
24-
self::PHONE => 'Phone',
25-
self::FAX => 'Fax',
26-
self::MOBILE => 'Mobile',
27-
self::WHATSAPP => 'Whatsapp',
24+
self::EMAIL => 'Email',
25+
self::PHONE => 'Phone',
26+
self::FAX => 'Fax',
27+
self::MOBILE => 'Mobile',
28+
self::WHATSAPP => 'Whatsapp',
29+
self::INVOICE_CC => 'Invoice CC Email',
2830
};
2931
}
3032

3133
public function color(): string
3234
{
3335
return match ($this) {
34-
self::EMAIL => 'info',
35-
self::PHONE => 'primary',
36-
self::FAX => 'gray',
37-
self::MOBILE => 'success',
38-
self::WHATSAPP => 'amber',
36+
self::EMAIL => 'info',
37+
self::PHONE => 'primary',
38+
self::FAX => 'gray',
39+
self::MOBILE => 'success',
40+
self::WHATSAPP => 'amber',
41+
self::INVOICE_CC => 'warning',
3942
};
4043
}
4144
}

Modules/Clients/Filament/Company/Resources/Relations/Tables/RelationsTable.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use Modules\Clients\Enums\RelationStatus;
1313
use Modules\Clients\Enums\RelationType;
1414
use Modules\Clients\Models\Relation;
15-
use Modules\Clients\Services\CustomerService;
15+
use Modules\Clients\Services\RelationService;
1616
use Modules\Core\Enums\Permission;
1717
use Modules\Core\Helpers\EnumHelper;
1818

@@ -91,7 +91,7 @@ public static function configure(Table $table): Table
9191
EditAction::make('edit')
9292
->visible(fn () => auth()->user()?->can(Permission::EDIT_RELATIONS->value))
9393
->action(function (Relation $record, array $data) {
94-
app(CustomerService::class)->updateCustomer($record, $data);
94+
app(RelationService::class)->updateRelation($record, $data);
9595
})
9696
->modalWidth('full'),
9797
DeleteAction::make('delete')

Modules/Clients/Models/Relation.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Illuminate\Database\Eloquent\Relations\HasMany;
1212
use Illuminate\Database\Eloquent\Relations\MorphMany;
1313
use Modules\Clients\Database\Factories\RelationFactory;
14+
use Modules\Clients\Enums\CommunicationType;
1415
use Modules\Clients\Enums\RelationStatus;
1516
use Modules\Clients\Enums\RelationType;
1617
use Modules\Core\Models\Company;
@@ -45,7 +46,7 @@
4546
* @property Contact $contact
4647
* @property string|null $currency_code
4748
* @property string|null $language
48-
* @property array|null $email_cc
49+
* @property array $email_cc
4950
* @property Company $company
5051
* @property Collection|Contact[] $contacts
5152
* @property Collection|Expense[] $expenses
@@ -66,11 +67,12 @@ class Relation extends Model
6667
'relation_type' => RelationType::class,
6768
'relation_status' => RelationStatus::class,
6869
'enable_e_invoicing' => 'boolean',
69-
'email_cc' => 'array',
7070
];
7171

7272
protected $guarded = [];
7373

74+
protected $appends = ['email_cc'];
75+
7476
/*
7577
|--------------------------------------------------------------------------
7678
| Static Methods
@@ -115,6 +117,11 @@ public function communications(): MorphMany
115117
return $this->morphMany(Communication::class, 'communicationable');
116118
}
117119

120+
public function ccEmailCommunications(): MorphMany
121+
{
122+
return $this->communications()->where('communication_type', CommunicationType::INVOICE_CC->value);
123+
}
124+
118125
public function contacts(): HasMany
119126
{
120127
return $this->hasMany(Contact::class);
@@ -180,6 +187,13 @@ public function getCustomerEmailAttribute()
180187
return $this->email;
181188
}
182189

190+
public function getEmailCcAttribute(): array
191+
{
192+
return $this->ccEmailCommunications()
193+
->pluck('communication_value')
194+
->all();
195+
}
196+
183197
/*public function getPrimaryContactAttribute(): string
184198
{
185199
return mb_trim($this->primary_ontact?->first_name . ' ' . $this->primary_contact?->last_name);

Modules/Clients/Services/RelationService.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Support\Facades\DB;
66
use Illuminate\Support\Str;
7+
use Modules\Clients\Enums\CommunicationType;
78
use Modules\Clients\Enums\RelationStatus;
89
use Modules\Clients\Enums\RelationType;
910
use Modules\Clients\Events\CustomerWasCreated;
@@ -40,7 +41,6 @@ public function createRelation(array $data): Relation
4041
'vat_number' => $data['vat_number'] ?? null,
4142
'currency_code' => $data['currency_code'] ?? null,
4243
'language' => $data['language'] ?? null,
43-
'email_cc' => $data['email_cc'] ?? null,
4444
'registered_at' => $data['registered_at'] ?? now(),
4545
]);
4646

@@ -52,6 +52,10 @@ public function createRelation(array $data): Relation
5252
$this->syncCommunications($relation, $data['communications']);
5353
}
5454

55+
if (isset($data['email_cc']) && is_array($data['email_cc'])) {
56+
$this->syncCcEmails($relation, $data['email_cc']);
57+
}
58+
5559
DB::commit();
5660

5761
event(new CustomerWasCreated());
@@ -80,7 +84,6 @@ public function updateRelation(Relation $relation, array $data): Relation
8084
'vat_number' => $data['vat_number'] ?? $relation->vat_number,
8185
'currency_code' => $data['currency_code'] ?? $relation->currency_code,
8286
'language' => $data['language'] ?? $relation->language,
83-
'email_cc' => $data['email_cc'] ?? $relation->email_cc,
8487
'registered_at' => $data['registered_at'] ?? $relation->registered_at,
8588
]);
8689

@@ -94,6 +97,10 @@ public function updateRelation(Relation $relation, array $data): Relation
9497
$this->syncCommunications($relation, $data['communications']);
9598
}
9699

100+
if (isset($data['email_cc']) && is_array($data['email_cc'])) {
101+
$this->syncCcEmails($relation, $data['email_cc']);
102+
}
103+
97104
DB::commit();
98105

99106
event(new CustomerWasUpdated());
@@ -161,4 +168,18 @@ protected function syncCommunications(Relation $relation, array $communications)
161168
$relation->communications()->delete();
162169
$relation->communications()->createMany($communicationsToSync);
163170
}
171+
172+
protected function syncCcEmails(Relation $relation, array $emails): void
173+
{
174+
$relation->ccEmailCommunications()->delete();
175+
176+
foreach ($emails as $email) {
177+
$relation->communications()->create([
178+
'company_id' => $relation->company_id,
179+
'communication_type' => CommunicationType::INVOICE_CC->value,
180+
'communication_value' => $email,
181+
'is_primary' => false,
182+
]);
183+
}
184+
}
164185
}

Modules/Clients/Tests/Feature/CustomersTest.php

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Support\Carbon;
77
use Illuminate\Support\Str;
88
use Livewire\Livewire;
9+
use Modules\Clients\Enums\CommunicationType;
910
use Modules\Clients\Enums\RelationStatus;
1011
use Modules\Clients\Enums\RelationType;
1112
use Modules\Clients\Filament\Company\Resources\Relations\Pages\CreateRelation;
@@ -429,21 +430,33 @@ public function it_only_lists_customers_for_the_current_tenant(): void
429430
# region cc emails
430431
#[Test]
431432
#[Group('crud')]
432-
public function it_stores_and_retrieves_cc_emails_as_an_array(): void
433+
public function it_stores_and_retrieves_cc_emails_as_communications(): void
433434
{
434435
/* Arrange */
435436
$cc = ['billing@acme.com', 'finance@acme.com'];
436437

437438
/* Act */
438-
$customer = Relation::factory()->for($this->company)->create(['email_cc' => $cc]);
439-
$loaded = Relation::find($customer->id);
439+
$customer = Relation::factory()->for($this->company)->create();
440+
foreach ($cc as $email) {
441+
$customer->communications()->create([
442+
'company_id' => $this->company->id,
443+
'communication_type' => CommunicationType::INVOICE_CC->value,
444+
'communication_value' => $email,
445+
'is_primary' => false,
446+
]);
447+
}
448+
$loaded = Relation::find($customer->id);
440449

441450
/* Assert */
442-
$this->assertEquals($cc, $loaded->email_cc);
443-
$this->assertDatabaseHas('relations', [
444-
'id' => $customer->id,
445-
'email_cc' => json_encode($cc),
446-
]);
451+
$this->assertEqualsCanonicalizing($cc, $loaded->email_cc);
452+
foreach ($cc as $email) {
453+
$this->assertDatabaseHas('communications', [
454+
'communicationable_id' => $customer->id,
455+
'communicationable_type' => Relation::class,
456+
'communication_type' => CommunicationType::INVOICE_CC->value,
457+
'communication_value' => $email,
458+
]);
459+
}
447460
}
448461

449462
#[Test]
@@ -471,10 +484,16 @@ public function it_creates_a_customer_with_cc_emails_through_a_modal(): void
471484
/* Assert */
472485
$component->assertSuccessful();
473486

474-
$this->assertDatabaseHas('relations', [
475-
'company_name' => $payload['company_name'],
476-
'email_cc' => json_encode($payload['email_cc']),
477-
]);
487+
$customer = Relation::where('company_name', $payload['company_name'])->firstOrFail();
488+
489+
foreach ($payload['email_cc'] as $email) {
490+
$this->assertDatabaseHas('communications', [
491+
'communicationable_id' => $customer->id,
492+
'communicationable_type' => Relation::class,
493+
'communication_type' => CommunicationType::INVOICE_CC->value,
494+
'communication_value' => $email,
495+
]);
496+
}
478497
}
479498

480499
#[Test]

0 commit comments

Comments
 (0)