diff --git a/app/Actions/ExportReport.php b/app/Actions/ExportReport.php
index f212633b..827edfba 100644
--- a/app/Actions/ExportReport.php
+++ b/app/Actions/ExportReport.php
@@ -21,6 +21,8 @@ class ExportReport extends Action
protected bool | null $showMissingValues = false;
+ protected bool | null $addCasesInMonitoring = false;
+
protected function setUp(): void
{
parent::setUp();
@@ -58,6 +60,13 @@ public function setShowMissingValues(?bool $showMissingValues): self
return $this;
}
+ public function setAddCasesInMonitoring(?bool $addCasesInMonitoring): self
+ {
+ $this->addCasesInMonitoring = $addCasesInMonitoring;
+
+ return $this;
+ }
+
public function generateExport(): BinaryFileResponse
{
$service = new BeneficiariesV2();
@@ -65,6 +74,7 @@ public function generateExport(): BinaryFileResponse
->setStartDate($this->startDate)
->setEndDate($this->endDate)
->setShowMissingValue($this->showMissingValues)
+ ->setAddCasesInMonitoring($this->addCasesInMonitoring)
->composeReport();
$fileName = \sprintf('%s_%s_%s.xlsx', $this->startDate, $this->endDate, $this->reportType->value);
diff --git a/app/Concerns/HasPermissions.php b/app/Concerns/HasPermissions.php
index a9c356d4..504962fa 100644
--- a/app/Concerns/HasPermissions.php
+++ b/app/Concerns/HasPermissions.php
@@ -78,4 +78,22 @@ public function hasAccessToCommunity()
return (bool) $this->permissions?->admin_permissions->contains(AdminPermission::CAN_CHANGE_ORGANISATION_PROFILE);
}
+
+ public function canSearchBeneficiary(): bool
+ {
+ if ($this->isNgoAdmin()) {
+ return true;
+ }
+
+ return $this->permissions?->case_permissions->contains(CasePermission::CAN_SEARCH_AND_COPY_CASES_IN_ALL_CENTERS);
+ }
+
+ public function hasAccessToReports(): bool
+ {
+ if ($this->isNgoAdmin()) {
+ return true;
+ }
+
+ return (bool) $this->permissions?->case_permissions->contains(CasePermission::HAS_ACCESS_TO_STATISTICS);
+ }
}
diff --git a/app/Concerns/LogsActivityOptions.php b/app/Concerns/LogsActivityOptions.php
index be13ad7e..5ebaa60f 100644
--- a/app/Concerns/LogsActivityOptions.php
+++ b/app/Concerns/LogsActivityOptions.php
@@ -5,6 +5,7 @@
namespace App\Concerns;
use App\Models\Activity;
+use Illuminate\Database\Eloquent\Relations\HasMany;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
@@ -31,4 +32,10 @@ public function tapActivity(Activity $activity, string $eventName)
$activity->event = $activity->subject_type;
$activity->subject()->associate($this->beneficiary);
}
+
+ public function activity(): HasMany
+ {
+ return $this->hasMany(Activity::class, 'subject_id')
+ ->where('subject_type', 'beneficiary');
+ }
}
diff --git a/app/Concerns/PreventMultipleSubmit.php b/app/Concerns/PreventMultipleSubmit.php
new file mode 100644
index 00000000..720fee73
--- /dev/null
+++ b/app/Concerns/PreventMultipleSubmit.php
@@ -0,0 +1,29 @@
+id());
+ $lock = Cache::lock($cacheKey, 5);
+
+ if (! $lock->get()) {
+ throw new Halt();
+ }
+ }
+
+ public function beforeSave(): void
+ {
+ $this->beforeCreate();
+ }
+}
diff --git a/app/Filament/Admin/Resources/BenefitResource/Pages/CreateBenefit.php b/app/Filament/Admin/Resources/BenefitResource/Pages/CreateBenefit.php
index 1c41f7a9..0a5bf179 100644
--- a/app/Filament/Admin/Resources/BenefitResource/Pages/CreateBenefit.php
+++ b/app/Filament/Admin/Resources/BenefitResource/Pages/CreateBenefit.php
@@ -4,12 +4,15 @@
namespace App\Filament\Admin\Resources\BenefitResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Admin\Resources\BenefitResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Contracts\Support\Htmlable;
class CreateBenefit extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = BenefitResource::class;
protected static bool $canCreateAnother = false;
diff --git a/app/Filament/Admin/Resources/InstitutionResource/Pages/CreateInstitution.php b/app/Filament/Admin/Resources/InstitutionResource/Pages/CreateInstitution.php
index 95568f40..680b8b23 100644
--- a/app/Filament/Admin/Resources/InstitutionResource/Pages/CreateInstitution.php
+++ b/app/Filament/Admin/Resources/InstitutionResource/Pages/CreateInstitution.php
@@ -4,6 +4,7 @@
namespace App\Filament\Admin\Resources\InstitutionResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Admin\Resources\InstitutionResource;
use App\Filament\Admin\Resources\UserInstitutionResource\Pages\EditUserInstitution;
use App\Forms\Components\Repeater;
@@ -17,6 +18,7 @@
class CreateInstitution extends CreateRecord
{
use HasWizard;
+ use PreventMultipleSubmit;
protected static string $resource = InstitutionResource::class;
diff --git a/app/Filament/Admin/Resources/OrganizationResource/Pages/CreateOrganization.php b/app/Filament/Admin/Resources/OrganizationResource/Pages/CreateOrganization.php
index e70abbc9..e3a9aec3 100644
--- a/app/Filament/Admin/Resources/OrganizationResource/Pages/CreateOrganization.php
+++ b/app/Filament/Admin/Resources/OrganizationResource/Pages/CreateOrganization.php
@@ -4,11 +4,14 @@
namespace App\Filament\Admin\Resources\OrganizationResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Admin\Resources\OrganizationResource;
use Filament\Resources\Pages\CreateRecord;
class CreateOrganization extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = OrganizationResource::class;
protected static bool $canCreateAnother = false;
diff --git a/app/Filament/Admin/Resources/ResultResource/Pages/CreateResult.php b/app/Filament/Admin/Resources/ResultResource/Pages/CreateResult.php
index 56a0b92f..35f8cf2e 100644
--- a/app/Filament/Admin/Resources/ResultResource/Pages/CreateResult.php
+++ b/app/Filament/Admin/Resources/ResultResource/Pages/CreateResult.php
@@ -4,12 +4,15 @@
namespace App\Filament\Admin\Resources\ResultResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Admin\Resources\ResultResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Contracts\Support\Htmlable;
class CreateResult extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = ResultResource::class;
protected static bool $canCreateAnother = false;
diff --git a/app/Filament/Admin/Resources/RoleResource/Pages/CreateRole.php b/app/Filament/Admin/Resources/RoleResource/Pages/CreateRole.php
index c7d958fd..bb0b48af 100644
--- a/app/Filament/Admin/Resources/RoleResource/Pages/CreateRole.php
+++ b/app/Filament/Admin/Resources/RoleResource/Pages/CreateRole.php
@@ -4,12 +4,15 @@
namespace App\Filament\Admin\Resources\RoleResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Admin\Resources\RoleResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Contracts\Support\Htmlable;
class CreateRole extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = RoleResource::class;
protected static bool $canCreateAnother = false;
diff --git a/app/Filament/Admin/Resources/ServiceResource/Pages/CreateService.php b/app/Filament/Admin/Resources/ServiceResource/Pages/CreateService.php
index fa64447d..a9eb84ec 100644
--- a/app/Filament/Admin/Resources/ServiceResource/Pages/CreateService.php
+++ b/app/Filament/Admin/Resources/ServiceResource/Pages/CreateService.php
@@ -4,12 +4,15 @@
namespace App\Filament\Admin\Resources\ServiceResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Admin\Resources\ServiceResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Contracts\Support\Htmlable;
class CreateService extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = ServiceResource::class;
protected static bool $canCreateAnother = false;
diff --git a/app/Filament/Admin/Resources/UserResource/Pages/CreateUser.php b/app/Filament/Admin/Resources/UserResource/Pages/CreateUser.php
index d69f1e44..4f3016ee 100644
--- a/app/Filament/Admin/Resources/UserResource/Pages/CreateUser.php
+++ b/app/Filament/Admin/Resources/UserResource/Pages/CreateUser.php
@@ -4,11 +4,14 @@
namespace App\Filament\Admin\Resources\UserResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Admin\Resources\UserResource;
use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = UserResource::class;
protected static bool $canCreateAnother = false;
diff --git a/app/Filament/Organizations/Pages/ReportsPage.php b/app/Filament/Organizations/Pages/ReportsPage.php
index 998fd995..f759c997 100644
--- a/app/Filament/Organizations/Pages/ReportsPage.php
+++ b/app/Filament/Organizations/Pages/ReportsPage.php
@@ -8,8 +8,12 @@
use App\Enums\ReportType;
use App\Forms\Components\ReportTable;
use Filament\Forms;
+use Filament\Forms\Components\Checkbox;
+use Filament\Forms\Components\DatePicker;
+use Filament\Forms\Components\Select;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Form;
+use Filament\Forms\Get;
use Filament\Infolists\Components\Section;
use Filament\Infolists\Contracts\HasInfolists;
use Filament\Infolists\Infolist;
@@ -17,6 +21,7 @@
use Filament\Pages\Page;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View;
+use Illuminate\Support\HtmlString;
class ReportsPage extends Page implements Forms\Contracts\HasForms, HasInfolists
{
@@ -37,6 +42,13 @@ class ReportsPage extends Page implements Forms\Contracts\HasForms, HasInfolists
public $show_missing_values;
+ public $add_cases_in_monitoring;
+
+ public static function canAccess(): bool
+ {
+ return auth()->user()->hasAccessToReports();
+ }
+
public static function getNavigationGroup(): ?string
{
return __('navigation.statistics._group');
@@ -69,22 +81,39 @@ protected function getFormSchema(): array
Forms\Components\Section::make()
->columns(4)
->schema([
- Forms\Components\Select::make('report_type')
+ Select::make('report_type')
->key('report_type')
->label(__('report.labels.report_type'))
->columnSpan(2)
->options(ReportType::options())
->searchable(),
- Forms\Components\DatePicker::make('start_date')
+ DatePicker::make('start_date')
->label(__('report.labels.start_date'))
- ->default(now()->startOfMonth()),
+ ->default(now()->startOfMonth())
+ ->maxDate(fn (Get $get) => $get('end_date') ? debug($get('end_date')) : now())
+ ->live(),
- Forms\Components\DatePicker::make('end_date')
+ DatePicker::make('end_date')
->label(__('report.labels.end_date'))
- ->default(now()),
+ ->default(now())
+ ->minDate(fn (Get $get) => $get('start_date') ?? null)
+ ->maxDate(now())
+ ->live(),
+
+ Checkbox::make('add_cases_in_monitoring')
+ ->label(
+ new HtmlString(
+ \sprintf(
+ '%s',
+ __('report.helpers.add_cases_in_monitoring'),
+ __('report.labels.add_cases_in_monitoring'),
+ )
+ )
+ )
+ ->columnSpan(2),
- Forms\Components\Checkbox::make('show_missing_values')
+ Checkbox::make('show_missing_values')
->label(__('report.labels.show_missing_values'))
->default(true)
->columnSpan(2),
@@ -107,7 +136,8 @@ public function infolist(Infolist $infolist): Infolist
->setReportType($this->report_type)
->setStartDate($this->start_date)
->setEndDate($this->end_date)
- ->setShowMissingValues($this->show_missing_values),
+ ->setShowMissingValues($this->show_missing_values)
+ ->setAddCasesInMonitoring($this->add_cases_in_monitoring),
])
->schema([
$this->reportTable(),
@@ -121,7 +151,8 @@ public function reportTable(): ReportTable
->setReportType($this->report_type ? ReportType::tryFrom($this->report_type) : null)
->setStartDate($this->start_date)
->setEndDate($this->end_date)
- ->setShowMissingValue($this->show_missing_values);
+ ->setShowMissingValue($this->show_missing_values)
+ ->setAddCasesInMonitoring($this->add_cases_in_monitoring);
}
public function render(): View
diff --git a/app/Filament/Organizations/Resources/BeneficiaryInterventionResource/Pages/CreateBeneficiaryIntervention.php b/app/Filament/Organizations/Resources/BeneficiaryInterventionResource/Pages/CreateBeneficiaryIntervention.php
index 111dbdd1..2a620f6f 100644
--- a/app/Filament/Organizations/Resources/BeneficiaryInterventionResource/Pages/CreateBeneficiaryIntervention.php
+++ b/app/Filament/Organizations/Resources/BeneficiaryInterventionResource/Pages/CreateBeneficiaryIntervention.php
@@ -4,10 +4,13 @@
namespace App\Filament\Organizations\Resources\BeneficiaryInterventionResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Organizations\Resources\BeneficiaryInterventionResource;
use Filament\Resources\Pages\CreateRecord;
class CreateBeneficiaryIntervention extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = BeneficiaryInterventionResource::class;
}
diff --git a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/CloseFile/CreateCloseFile.php b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/CloseFile/CreateCloseFile.php
index a7baf168..6bdfc8c0 100644
--- a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/CloseFile/CreateCloseFile.php
+++ b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/CloseFile/CreateCloseFile.php
@@ -4,6 +4,7 @@
namespace App\Filament\Organizations\Resources\BeneficiaryResource\Pages\CloseFile;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Organizations\Resources\BeneficiaryResource;
use App\Models\Specialist;
use App\Services\Breadcrumb\BeneficiaryBreadcrumb;
@@ -18,6 +19,7 @@
class CreateCloseFile extends EditRecord
{
use HasWizard;
+ use PreventMultipleSubmit;
protected static string $resource = BeneficiaryResource::class;
diff --git a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/CreateBeneficiary.php b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/CreateBeneficiary.php
index a008d4a1..91bb9104 100644
--- a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/CreateBeneficiary.php
+++ b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/CreateBeneficiary.php
@@ -4,14 +4,20 @@
namespace App\Filament\Organizations\Resources\BeneficiaryResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Enums\AddressType;
use App\Filament\Organizations\Resources\BeneficiaryResource;
+use App\Forms\Components\Notice;
+use App\Forms\Components\Radio;
use App\Models\Beneficiary;
+use App\Models\Organization;
+use App\Models\Scopes\BelongsToCurrentTenant;
use App\Rules\ValidCNP;
+use Filament\Facades\Filament;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Grid;
-use Filament\Forms\Components\Hidden;
+use Filament\Forms\Components\Group;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput;
@@ -21,11 +27,14 @@
use Filament\Resources\Pages\CreateRecord;
use Filament\Resources\Pages\CreateRecord\Concerns\HasWizard;
use Illuminate\Contracts\Support\Htmlable;
+use Illuminate\Database\Query\Builder;
use Illuminate\Support\HtmlString;
+use Illuminate\Validation\Rules\Unique;
class CreateBeneficiary extends CreateRecord
{
use HasWizard;
+ use PreventMultipleSubmit;
protected static string $resource = BeneficiaryResource::class;
@@ -72,7 +81,7 @@ protected function setParentBeneficiary(): void
public function getStartStep(): int
{
- return $this->parentBeneficiary ? 2 : 1;
+ return $this->parentBeneficiary ? 3 : 1;
}
protected function getSteps(): array
@@ -94,53 +103,191 @@ protected function getSteps(): array
->hiddenLabel()
->columnSpanFull()
->content(__('beneficiary.placeholder.consent')),
-
- Placeholder::make('consent_placeholder')
- ->hiddenLabel()
- ->columnSpanFull()
- ->content(new HtmlString('' . __('beneficiary.placeholder.check_beneficiary_exists') . '')),
-
+ ]),
+ ]),
+ Step::make(__('field.cnp'))
+ ->schema([
+ Group::make()
+ ->maxWidth('3xl')
+ ->schema([
TextInput::make('cnp')
- ->label(__('field.cnp'))
- ->nullable()
+ ->label(__('field.beneficiary_cnp'))
+ ->placeholder(__('placeholder.cnp'))
+ ->maxLength(13)
+ ->mask('9999999999999')
->rule(new ValidCNP)
- ->hidden()
- ->hintAction(
- Action::make('check_cnp')
- ->label(__('field.check'))
- ->action(function (Get $get, Set $set) {
- $beneficiary = Beneficiary::query()
- ->where('cnp', $get('cnp'))
- ->first();
- if ($beneficiary !== null) {
- $set('beneficiary_status', 1);
- } else {
- $set('beneficiary_status', 0);
- }
- }),
+ ->unique(
+ ignorable: $this->parentBeneficiary,
+ ignoreRecord: true,
+ modifyRuleUsing: function (Unique $rule, ?Beneficiary $record) {
+ $initialID = 0;
+ if ($this->parentBeneficiary?->id) {
+ $initialID = $parentBeneficiary->initial_id ?? $this->parentBeneficiary->id;
+ }
+ if (! $initialID && $record) {
+ $initialID = $record->initial_id ?? $record->id;
+ }
+
+ return
+ $rule->where(fn (Builder $query) => $query->whereNot('id', $initialID)
+ ->where(fn (Builder $query) => $query->whereNot('initial_id', $initialID)
+ ->orWhereNull('initial_id')))
+ ->where('organization_id', Filament::getTenant()->id);
+ }
)
- ->lazy(),
+ ->live()
+ ->disabled(fn (Get $get) => $get('without_cnp')),
- Hidden::make('beneficiary_status')
+ Checkbox::make('without_cnp')
+ ->label(__('field.without_cnp'))
->live(),
- Placeholder::make('beneficiary_exists')
- ->hiddenLabel()
- ->columnSpanFull()
- ->content(new HtmlString(__('beneficiary.placeholder.beneficiary_exists')))
- ->visible(fn (Get $get) => $get('beneficiary_status') === 1),
+ Notice::make('beneficiary_exist')
+ ->key('beneficiary_exist')
+ ->color('primary')
+ ->visible(
+ fn (Get $get) => auth()->user()->canSearchBeneficiary() ?
+ Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->whereIn(
+ 'organization_id',
+ auth()->user()
+ ->organizations
+ ->filter(fn (Organization $organization) => $organization->institution_id == Filament::getTenant()->institution_id)
+ ->pluck('id')
+ ->toArray()
+ )
+ ->withoutGlobalScopes([BelongsToCurrentTenant::class])
+ ->first() :
+ Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->first()
+ )
+ ->content(function (Get $get) {
+ return new HtmlString(__('beneficiary.placeholder.beneficiary_exists'));
+ $beneficiary = Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->first();
- Placeholder::make('beneficiary_not_exists')
- ->hiddenLabel()
- ->columnSpanFull()
- ->content(new HtmlString(__('beneficiary.placeholder.beneficiary_not_exists')))
- ->visible(fn (Get $get) => $get('beneficiary_status') === 0),
+ if (! $beneficiary) {
+ $organizations = auth()->user()->organizations
+ ->filter(fn (Organization $organization) => $organization->institution_id == Filament::getTenant()->institution_id);
+ $beneficiary = Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->whereIn('organization_id', $organizations->pluck('id')->toArray())
+ ->withoutGlobalScopes([BelongsToCurrentTenant::class])
+ ->with('organization')
+ ->first();
+
+ if (! $beneficiary) {
+ return '';
+ }
+
+ return new HtmlString(__('beneficiary.placeholder.beneficiary_exists', [
+ 'url' => BeneficiaryResource::getUrl('view', ['record' => $beneficiary, 'tenant' => $beneficiary->organization]),
+ ]));
+ }
+
+ return new HtmlString(__('beneficiary.placeholder.beneficiary_exists', [
+ 'url' => BeneficiaryResource::getUrl('view', ['record' => $beneficiary]),
+ ]));
+ })
+ ->registerActions([
+ Action::make('view_beneficiary')
+ ->label(__('general.action.view_details'))
+ ->link()
+ ->url(
+ fn (Get $get) => BeneficiaryResource::getUrl('view', [
+ 'record' => Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->first(),
+ ])
+ )
+ ->visible(
+ fn (Get $get) => Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->first()
+ ),
+
+ Action::make('view_beneficiary_from_another_tenant')
+ ->label(__('general.action.view_details'))
+ ->link()
+ ->modalHeading(__('beneficiary.headings.modal_create_beneficiary_from_anther_tenant'))
+ ->form([
+ Radio::make('copy_beneficiary')
+ ->label(__('beneficiary.labels.beneficiary_exist'))
+ ->options([
+ 'yes' => __('beneficiary.labels.copy_data_from_another_tenant'),
+ 'no' => __('beneficiary.labels.continue_register_without_copy'),
+ ]),
+ ])
+ ->modalSubmitActionLabel(__('beneficiary.action.register'))
+ ->action(function (array $data, Get $get, Set $set): void {
+ if ($data['copy_beneficiary'] !== 'yes') {
+ return;
+ }
+
+ $beneficiary = Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->whereIn(
+ 'organization_id',
+ auth()->user()
+ ->organizations
+ ->filter(
+ fn (Organization $organization) => $organization->institution_id == Filament::getTenant()->institution_id
+ && $organization !== Filament::getTenant()
+ )
+ ->pluck('id')
+ ->toArray()
+ )
+ ->withoutGlobalScopes([BelongsToCurrentTenant::class])
+ ->with(['effective_residence', 'legal_residence'])
+ ->first();
+
+ $ignoredFields = [
+ 'id',
+ 'initial_id',
+ 'doesnt_have_children',
+ 'children_total_count',
+ 'children_care_count',
+ 'children_under_18_care_count',
+ 'children_18_care_count',
+ 'children_accompanying_count',
+ ];
+ foreach ($beneficiary->toArray() as $beneficiaryKey => $beneficiaryValue) {
+ if (\in_array($beneficiaryKey, $ignoredFields)) {
+ continue;
+ }
+ $set($beneficiaryKey, $beneficiaryValue);
+ }
+ })
+ ->visible(
+ fn (Get $get) => ! Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->first() &&
+ Beneficiary::query()
+ ->where('cnp', $get('cnp'))
+ ->whereIn(
+ 'organization_id',
+ auth()->user()
+ ->organizations
+ ->filter(
+ fn (Organization $organization) => $organization->institution_id == Filament::getTenant()->institution_id
+ && $organization !== Filament::getTenant()
+ )
+ ->pluck('id')
+ ->toArray()
+ )
+ ->withoutGlobalScopes([BelongsToCurrentTenant::class])
+ ->first()
+ ),
+ ]),
]),
]),
Step::make('beneficiary')
->label(__('beneficiary.wizard.beneficiary.label'))
- ->schema(EditBeneficiaryIdentity::getBeneficiaryIdentityFormSchema($this->parentBeneficiary))
+ ->schema(EditBeneficiaryIdentity::getBeneficiaryIdentityFormSchema($this->parentBeneficiary, false))
->afterStateHydrated(function (Set $set) {
$legalResidence = AddressType::LEGAL_RESIDENCE->value;
$effectiveResidence = AddressType::EFFECTIVE_RESIDENCE->value;
diff --git a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/DetailedEvaluation/CreateDetailedEvaluation.php b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/DetailedEvaluation/CreateDetailedEvaluation.php
index 93a706f3..0416760f 100644
--- a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/DetailedEvaluation/CreateDetailedEvaluation.php
+++ b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/DetailedEvaluation/CreateDetailedEvaluation.php
@@ -4,6 +4,7 @@
namespace App\Filament\Organizations\Resources\BeneficiaryResource\Pages\DetailedEvaluation;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Organizations\Resources\BeneficiaryResource;
use App\Models\BeneficiaryPartner;
use App\Services\Breadcrumb\BeneficiaryBreadcrumb;
@@ -15,6 +16,7 @@
class CreateDetailedEvaluation extends EditRecord
{
use HasWizard;
+ use PreventMultipleSubmit;
protected static string $resource = BeneficiaryResource::class;
diff --git a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/EditBeneficiaryIdentity.php b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/EditBeneficiaryIdentity.php
index 7d08061a..09a74ca0 100644
--- a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/EditBeneficiaryIdentity.php
+++ b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/EditBeneficiaryIdentity.php
@@ -74,73 +74,79 @@ public function form(Form $form): Form
]);
}
- public static function getBeneficiaryIdentityFormSchema(?Beneficiary $parentBeneficiary = null): array
+ public static function getBeneficiaryIdentityFormSchema(?Beneficiary $parentBeneficiary = null, bool $withCnpField = true): array
{
+ $firstPartOfSchema = [
+ Hidden::make('initial_id'),
+
+ TextInput::make('last_name')
+ ->label(__('field.last_name'))
+ ->placeholder(__('placeholder.last_name'))
+ ->maxLength(50)
+ ->required(),
+
+ TextInput::make('first_name')
+ ->label(__('field.first_name'))
+ ->placeholder(__('placeholder.first_name'))
+ ->maxLength(50)
+ ->required(),
+
+ TextInput::make('prior_name')
+ ->label(__('field.prior_name'))
+ ->placeholder(__('placeholder.prior_name'))
+ ->maxLength(50)
+ ->nullable(),
+
+ Select::make('civil_status')
+ ->label(__('field.civil_status'))
+ ->placeholder(__('placeholder.civil_status'))
+ ->options(CivilStatus::options())
+ ->enum(CivilStatus::class),
+ ];
+
+ if ($withCnpField) {
+ $firstPartOfSchema[] = TextInput::make('cnp')
+ ->label(__('field.cnp'))
+ ->placeholder(__('placeholder.cnp'))
+ ->maxLength(13)
+ ->mask('9999999999999')
+ ->unique(
+ ignorable: $parentBeneficiary,
+ ignoreRecord: true,
+ modifyRuleUsing: function (Unique $rule, ?Beneficiary $record) use ($parentBeneficiary) {
+ $initialID = 0;
+ if ($parentBeneficiary?->id) {
+ $initialID = $parentBeneficiary->initial_id ?? $parentBeneficiary->id;
+ }
+ if (! $initialID && $record) {
+ $initialID = $record->initial_id ?? $record->id;
+ }
+
+ return
+ $rule->where(fn (Builder $query) => $query->whereNot('id', $initialID)
+ ->where(fn (Builder $query) => $query->whereNot('initial_id', $initialID)
+ ->orWhereNull('initial_id')));
+ }
+ )
+ ->nullable()
+ ->rule(new ValidCNP)
+ ->lazy()
+ ->afterStateUpdated(function (?string $state, Set $set) {
+ if ($state === null) {
+ return;
+ }
+
+ if (filled($birthdate = (new Cnp($state))->getBirthDateFromCNP())) {
+ $set('birthdate', $birthdate);
+ }
+ });
+ }
+
return [
Grid::make()
->maxWidth('3xl')
->schema([
- Hidden::make('initial_id'),
-
- TextInput::make('last_name')
- ->label(__('field.last_name'))
- ->placeholder(__('placeholder.last_name'))
- ->maxLength(50)
- ->required(),
-
- TextInput::make('first_name')
- ->label(__('field.first_name'))
- ->placeholder(__('placeholder.first_name'))
- ->maxLength(50)
- ->required(),
-
- TextInput::make('prior_name')
- ->label(__('field.prior_name'))
- ->placeholder(__('placeholder.prior_name'))
- ->maxLength(50)
- ->nullable(),
-
- Select::make('civil_status')
- ->label(__('field.civil_status'))
- ->placeholder(__('placeholder.civil_status'))
- ->options(CivilStatus::options())
- ->enum(CivilStatus::class),
-
- TextInput::make('cnp')
- ->label(__('field.cnp'))
- ->placeholder(__('placeholder.cnp'))
- ->maxLength(13)
- ->mask('9999999999999')
- ->unique(
- ignorable: $parentBeneficiary,
- ignoreRecord: true,
- modifyRuleUsing: function (Unique $rule, ?Beneficiary $record) use ($parentBeneficiary) {
- $initialID = 0;
- if ($parentBeneficiary?->id) {
- $initialID = $parentBeneficiary->initial_id ?? $parentBeneficiary->id;
- }
- if (! $initialID && $record) {
- $initialID = $record->initial_id ?? $record->id;
- }
-
- return
- $rule->where(fn (Builder $query) => $query->whereNot('id', $initialID)
- ->where(fn (Builder $query) => $query->whereNot('initial_id', $initialID)
- ->orWhereNull('initial_id')));
- }
- )
- ->nullable()
- ->rule(new ValidCNP)
- ->lazy()
- ->afterStateUpdated(function (?string $state, Set $set) {
- if ($state === null) {
- return;
- }
-
- if (filled($birthdate = (new Cnp($state))->getBirthDateFromCNP())) {
- $set('birthdate', $birthdate);
- }
- }),
+ ...$firstPartOfSchema,
Select::make('gender')
->label(__('field.gender'))
diff --git a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/InitialEvaluation/CreateInitialEvaluation.php b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/InitialEvaluation/CreateInitialEvaluation.php
index 11956cf5..7f5a9c4d 100644
--- a/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/InitialEvaluation/CreateInitialEvaluation.php
+++ b/app/Filament/Organizations/Resources/BeneficiaryResource/Pages/InitialEvaluation/CreateInitialEvaluation.php
@@ -4,6 +4,7 @@
namespace App\Filament\Organizations\Resources\BeneficiaryResource\Pages\InitialEvaluation;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Organizations\Resources\BeneficiaryResource;
use App\Services\Breadcrumb\BeneficiaryBreadcrumb;
use Filament\Forms\Components\Wizard\Step;
@@ -14,6 +15,7 @@
class CreateInitialEvaluation extends EditRecord
{
use HasWizard;
+ use PreventMultipleSubmit;
protected static string $resource = BeneficiaryResource::class;
diff --git a/app/Filament/Organizations/Resources/MonitoringResource/Pages/CreateMonitoring.php b/app/Filament/Organizations/Resources/MonitoringResource/Pages/CreateMonitoring.php
index bf177b49..c3c6ca3e 100644
--- a/app/Filament/Organizations/Resources/MonitoringResource/Pages/CreateMonitoring.php
+++ b/app/Filament/Organizations/Resources/MonitoringResource/Pages/CreateMonitoring.php
@@ -5,6 +5,7 @@
namespace App\Filament\Organizations\Resources\MonitoringResource\Pages;
use App\Concerns\HasParentResource;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Organizations\Resources\MonitoringResource;
use App\Models\Monitoring;
use App\Models\Specialist;
@@ -21,6 +22,7 @@ class CreateMonitoring extends CreateRecord
{
use HasWizard;
use HasParentResource;
+ use PreventMultipleSubmit;
protected static string $resource = MonitoringResource::class;
diff --git a/app/Filament/Organizations/Resources/ServiceResource/Pages/CreateService.php b/app/Filament/Organizations/Resources/ServiceResource/Pages/CreateService.php
index 1cd2221d..15b57afc 100644
--- a/app/Filament/Organizations/Resources/ServiceResource/Pages/CreateService.php
+++ b/app/Filament/Organizations/Resources/ServiceResource/Pages/CreateService.php
@@ -4,12 +4,15 @@
namespace App\Filament\Organizations\Resources\ServiceResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Organizations\Resources\ServiceResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Contracts\Support\Htmlable;
class CreateService extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = ServiceResource::class;
protected static bool $canCreateAnother = false;
diff --git a/app/Filament/Organizations/Resources/UserResource/Pages/CreateUser.php b/app/Filament/Organizations/Resources/UserResource/Pages/CreateUser.php
index 5d0e5588..e3f8652e 100644
--- a/app/Filament/Organizations/Resources/UserResource/Pages/CreateUser.php
+++ b/app/Filament/Organizations/Resources/UserResource/Pages/CreateUser.php
@@ -4,6 +4,7 @@
namespace App\Filament\Organizations\Resources\UserResource\Pages;
+use App\Concerns\PreventMultipleSubmit;
use App\Filament\Organizations\Resources\UserResource;
use App\Models\User;
use Filament\Facades\Filament;
@@ -12,6 +13,8 @@
class CreateUser extends CreateRecord
{
+ use PreventMultipleSubmit;
+
protected static string $resource = UserResource::class;
protected static bool $canCreateAnother = false;
diff --git a/app/Forms/Components/ReportTable.php b/app/Forms/Components/ReportTable.php
index 1effe928..f126f3c5 100644
--- a/app/Forms/Components/ReportTable.php
+++ b/app/Forms/Components/ReportTable.php
@@ -5,7 +5,6 @@
namespace App\Forms\Components;
use App\Enums\ReportType;
-use App\Services\Reports\Beneficiaries;
use App\Services\Reports\BeneficiariesV2;
use Filament\Infolists\Components\Component;
use Illuminate\Support\Collection;
@@ -14,7 +13,7 @@ class ReportTable extends Component
{
protected string $view = 'forms.components.report-table';
- protected Beneficiaries | BeneficiariesV2 $reportService;
+ protected BeneficiariesV2 $reportService;
protected ReportType | null $reportType = null;
@@ -24,6 +23,8 @@ class ReportTable extends Component
protected bool | null $showMissingValues = false;
+ protected bool | null $addCasesInMonitoring = false;
+
public static function make(string | null $id = null): static
{
$static = app(static::class, ['id' => $id]);
@@ -36,7 +37,6 @@ protected function setUp(): void
{
parent::setUp();
$this->reportService = new BeneficiariesV2();
-// $this->reportService = new Beneficiaries();
}
public function setReportType(ReportType | string | null $reportType): self
@@ -71,14 +71,17 @@ public function setShowMissingValue(?bool $showMissingValue): self
return $this;
}
- public function composeReport(): void
+ public function setAddCasesInMonitoring(?bool $addCasesInMonitoring): self
{
- $this->reportService->composeReport();
+ $this->addCasesInMonitoring = $addCasesInMonitoring;
+ $this->reportService->setAddCasesInMonitoring($addCasesInMonitoring);
+
+ return $this;
}
- public function getReportType(): ?ReportType
+ public function composeReport(): void
{
- return $this->reportService->getReportType();
+ $this->reportService->composeReport();
}
public function getReportData(): Collection
diff --git a/app/Services/Reports/BeneficiariesReports/BaseGenerator.php b/app/Services/Reports/BeneficiariesReports/BaseGenerator.php
index 9d236c41..dd082da8 100644
--- a/app/Services/Reports/BeneficiariesReports/BaseGenerator.php
+++ b/app/Services/Reports/BeneficiariesReports/BaseGenerator.php
@@ -4,38 +4,45 @@
namespace App\Services\Reports\BeneficiariesReports;
+use App\Enums\ActivityDescription;
+use App\Enums\CaseStatus;
use App\Models\Beneficiary;
+use Carbon\Carbon;
+use DB;
+use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Collection;
abstract class BaseGenerator
{
- protected string | null $startDate;
+ protected string | null $startDate = null;
protected string | null $endDate = null;
protected bool | null $showMissingValues = false;
+ protected bool | null $addCasesInMonitoring = false;
+
protected $query;
public function __construct()
{
$this->query = Beneficiary::query()
- ->leftJoin('close_files', 'beneficiaries.id', '=', 'close_files.beneficiary_id')
- ->toBase()
->selectRaw('COUNT(*) as total_cases');
}
public function setStartDate(?string $startDate): self
{
- $this->startDate = $startDate;
+ $this->startDate = $startDate ? Carbon::parse($startDate)->startOfDay()->format('Y-m-d H:i:s') : null;
return $this;
}
public function setEndDate(?string $endDate): self
{
- $this->endDate = $endDate;
+ $this->endDate = $endDate ?
+ Carbon::parse($endDate)->endOfDay()->format('Y-m-d H:i:s') :
+ Carbon::now()->endOfDay()->format('Y-m-d H:i:s');
return $this;
}
@@ -47,6 +54,13 @@ public function setShowMissingValues(?bool $showMissingValues): self
return $this;
}
+ public function setAddCasesInMonitoring(?bool $addCasesInMonitoring): self
+ {
+ $this->addCasesInMonitoring = $addCasesInMonitoring;
+
+ return $this;
+ }
+
public function getReportData(): Collection
{
$this->setSelectedFields();
@@ -56,6 +70,7 @@ public function getReportData(): Collection
->groupBy($this->getGroupBy());
return $this->query
+ ->toBase()
->get();
}
@@ -89,16 +104,70 @@ public function addConditions(): void
}
}
- if ($this->endDate) {
- $this->query->where('beneficiaries.created_at', '<=', $this->endDate . ' 23:59:59');
- }
+ $this->addDateConditions();
+ }
- if ($this->startDate) {
- $this->query->where(
- fn (Builder $query) => $query->where('close_files.date', '>=', $this->startDate)
- ->orWhereNull('close_files.date')
+ public function addDateConditions(): void
+ {
+ $this->query
+ ->when(
+ $this->startDate,
+ fn (EloquentBuilder $query) => $query
+ ->whereHas(
+ 'activity',
+ fn (EloquentBuilder $query) => $query
+ ->where(
+ fn (EloquentBuilder $query) => $query->whereJsonContains('properties->attributes->status', CaseStatus::ACTIVE->value)
+ ->when(
+ $this->addCasesInMonitoring,
+ fn (EloquentBuilder $query) => $query->orWhereJsonContains('properties->attributes->status', CaseStatus::MONITORED->value)
+ )
+ )
+ ->where('created_at', '<=', $this->endDate)
+ ->whereIn('activity_log.description', [ActivityDescription::CREATED->value, ActivityDescription::UPDATED->value])
+ ->whereNotExists(
+ fn (Builder $subQuery) => $subQuery->select(DB::raw(1))
+ ->from('activity_log as sublog')
+ ->whereColumn('sublog.subject_id', 'activity_log.subject_id')
+ ->whereIn('sublog.description', [
+ ActivityDescription::CREATED->value,
+ ActivityDescription::UPDATED->value,
+ ])
+ ->where('sublog.subject_type', 'beneficiary')
+ ->whereColumn('sublog.created_at', '>', 'activity_log.created_at')
+ ->whereJsonContainsKey('properties->attributes->status')
+ ->where('sublog.created_at', '<=', $this->endDate)
+ )
+ )
+ ->orWhereHas(
+ 'activity',
+ fn (EloquentBuilder $query) => $query->whereJsonContains('properties->old->status', CaseStatus::ACTIVE->value)
+ ->when(
+ $this->addCasesInMonitoring,
+ fn (EloquentBuilder $query) => $query->orWhereJsonContains('properties->old->status', CaseStatus::MONITORED->value)
+ )
+ ->whereBetween('created_at', [$this->startDate, $this->endDate])
+ )
+ )
+ ->when(
+ ! $this->startDate,
+ fn (EloquentBuilder $query) => $query
+ ->whereHas(
+ 'activity',
+ fn (EloquentBuilder $query) => $query
+ ->where(
+ fn (EloquentBuilder $query) => $query
+ ->whereJsonContains('properties->attributes->status', CaseStatus::ACTIVE->value)
+ ->when(
+ $this->addCasesInMonitoring,
+ fn (EloquentBuilder $query) => $query->orWhereJsonContains('properties->attributes->status', CaseStatus::MONITORED->value)
+ )
+ )
+ ->whereIn('description', [ActivityDescription::CREATED->value, ActivityDescription::UPDATED->value])
+ ->where('created_at', '<=', $this->endDate)
+ ->where('subject_type', 'beneficiary')
+ )
);
- }
}
public function addRelatedTables(): void
diff --git a/app/Services/Reports/BeneficiariesV2.php b/app/Services/Reports/BeneficiariesV2.php
index f5baa90d..01f239be 100644
--- a/app/Services/Reports/BeneficiariesV2.php
+++ b/app/Services/Reports/BeneficiariesV2.php
@@ -20,6 +20,8 @@ class BeneficiariesV2
protected bool | null $showMissingValue = false;
+ protected bool | null $addCasesInMonitoring = false;
+
public function setReportType(ReportType | string | null $reportType): self
{
$this->reportType = $reportType;
@@ -48,6 +50,13 @@ public function setShowMissingValue(?bool $showMissingValue): self
return $this;
}
+ public function setAddCasesInMonitoring(?bool $addCasesInMonitoring): self
+ {
+ $this->addCasesInMonitoring = $addCasesInMonitoring;
+
+ return $this;
+ }
+
public function composeReport(): void
{
$generatorClass = str_replace(' ', '', ucwords(str_replace('_', ' ', $this->reportType->value)));
@@ -61,7 +70,8 @@ public function composeReport(): void
$this->generator
->setStartDate($this->startDate)
->setEndDate($this->endDate)
- ->setShowMissingValues($this->showMissingValue);
+ ->setShowMissingValues($this->showMissingValue)
+ ->setAddCasesInMonitoring($this->addCasesInMonitoring);
}
public function getReportData(): Collection
diff --git a/lang/ro/beneficiary.php b/lang/ro/beneficiary.php
index 17834041..da49ab80 100644
--- a/lang/ro/beneficiary.php
+++ b/lang/ro/beneficiary.php
@@ -14,6 +14,10 @@
'reactivated' => 'Reactivare de caz',
'related_cases' => 'Istoric caz (fișe conectate cazului)',
'case_manager' => 'Manager de caz',
+ 'beneficiary_exist' => 'Beneficiarul cu CNP-ul introdus există în baza de date.',
+ 'copy_data_from_another_tenant' => 'Copiază datele de identificare în noul dosar de management de caz',
+ 'continue_register_without_copy' => 'Continuă cu adăugarea beneficiarului, fără copierea datelor de identificare în noul dosar de management de caz',
+
],
'page' => [
@@ -459,6 +463,7 @@
'action' => [
'create' => 'Înregistrează caz nou',
+ 'register' => 'Înregistrează caz',
'add_child' => 'Adaugă copil',
'add_row' => 'Adauga inca un rand',
'add_meet_row' => 'Adauga inca o intrevedere',
@@ -480,6 +485,10 @@
'personal_information' => 'Informații caz',
],
+ 'headings' => [
+ 'modal_create_beneficiary_from_anther_tenant' => 'Beneficiar identificat în baza de date',
+ ],
+
'placeholder' => [
'full_name' => 'Introdu nume si prenume',
'first_name' => 'Nume de familie',
@@ -510,9 +519,7 @@
'description_of_situation' => 'Descrieți pe scurt situația',
'email' => 'Introdu un email',
'consent' => 'Odată înregistrat cazul în sistem, aceste formulare de obținere a consimțământului vor putea fi încarcate în sistem, în secțiunea Documente Beneficiar.',
- 'check_beneficiary_exists' => 'Verifică dacă beneficiarul există în baza de date (Opțional)',
- 'beneficiary_exists' => 'CNP-ul a fost identificat în această bază de date, asociat cazului Maria Popescu. Vezi detalii',
- 'beneficiary_not_exists' => 'CNP-ul nu a fost identificat în această bază de date și nici în cea a altor centre ale instituției.',
+ 'beneficiary_exists' => 'CNP-ul a fost identificat în această bază de date.',
'file_name' => 'Nume document',
'reactivate_text_1' => 'Prin reactivarea unui caz se va duplica dosarului beneficiarului pentru a putea fi completat cu informații noi, fără a pierde informațiile despre evaluările și managementul de caz anterior.',
'reactivate_text_2' => 'Toate datele de identitate se vor copia din dosarul curent și pot fi actualizate manual pentru această nouă reactivare. Toate formularele vor fi disponibile pentru a fi completate cu informații noi.',
diff --git a/lang/ro/field.php b/lang/ro/field.php
index 5b2a4fbf..b72b563a 100644
--- a/lang/ro/field.php
+++ b/lang/ro/field.php
@@ -14,6 +14,8 @@
'city' => 'Localitate',
'civil_status' => 'Stare civilă',
'cnp' => 'CNP',
+ 'beneficiary_cnp' => 'CNP-ul beneficiarului',
+ 'without_cnp' => 'Nu deține / Nu știe',
'contact_notes' => 'Notițe legate de contactare beneficiar',
'county' => 'Județ',
'create_beneficiary_consent' => 'Confirm că s-a obținut acordul beneficiarului pentru înregistrarea datelor personale și utilizarea datelor rezultate din evaluare și intervenție în scopul oferirii serviciilor de management de caz.',
diff --git a/lang/ro/report.php b/lang/ro/report.php
index b57b5229..3ff177c2 100644
--- a/lang/ro/report.php
+++ b/lang/ro/report.php
@@ -11,6 +11,7 @@
'end_date' => 'Dată final raportare',
'show_missing_values' => 'Afișează și datele lipsă (missing values) în tabel',
'total' => 'Total cazuri',
+ 'add_cases_in_monitoring' => 'Include și cazurile în monitorizare',
],
'table_heading' => [
@@ -93,4 +94,8 @@
'generate' => 'Generează raport',
'export' => 'Exportă date',
],
+
+ 'helpers' => [
+ 'add_cases_in_monitoring' => 'Sistemul include în statistici toți beneficiarii care au avut un caz cu status DESCHIS cel puțin o zi în intervalul de referință (definit de datele de început/final raportare). Bifarea acestei opțiuni va include și cazurile cu status ÎN MONITORIZARE în statisticile raportate.',
+ ],
];