- Implemented RentPaymentHistoryServiceTest to validate payment retrieval with refunds and reversals. - Created ReverseRentPaymentServiceTest to ensure correct handling of payment reversals and allocation releases. - Developed rent-payment-allocation-dialog component with form for surplus allocation. - Added rent-payment-refund-dialog component for processing refunds with validation. - Introduced rent-payment-reversal-dialog component for reversing payments with reason input. - Implemented utility functions for formatting Euro values and handling date formatting. - Enhanced rent-payment-dialogs.spec.ts to cover new dialog functionalities and error handling.
104 lines
3.6 KiB
TypeScript
104 lines
3.6 KiB
TypeScript
import { Component, computed, inject, signal } from '@angular/core';
|
||
import {
|
||
AbstractControl,
|
||
FormControl,
|
||
FormGroup,
|
||
ReactiveFormsModule,
|
||
ValidationErrors,
|
||
Validators,
|
||
} from '@angular/forms';
|
||
import { MatButtonModule } from '@angular/material/button';
|
||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||
import { MatInputModule } from '@angular/material/input';
|
||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||
import { toSignal } from '@angular/core/rxjs-interop';
|
||
import { finalize } from 'rxjs';
|
||
import { RentDue } from '../../services/lease.service';
|
||
import { httpErrorMessage } from '../../services/http-error-message';
|
||
import { formatEuro, utcIsoDate } from '../../services/rent-payment-format';
|
||
import { RentPaymentService } from '../../services/rent-payment.service';
|
||
import { isRentPaymentDataStale, RENT_PAYMENT_DATA_STALE } from '../rent-payment-dialog-result';
|
||
|
||
export interface RentPaymentValidationDialogData {
|
||
rentDue: RentDue;
|
||
apartmentName: string;
|
||
}
|
||
|
||
@Component({
|
||
selector: 'app-rent-payment-validation-dialog',
|
||
imports: [
|
||
ReactiveFormsModule,
|
||
MatDialogModule,
|
||
MatButtonModule,
|
||
MatFormFieldModule,
|
||
MatInputModule,
|
||
MatProgressSpinnerModule,
|
||
],
|
||
templateUrl: './rent-payment-validation-dialog.html',
|
||
styleUrl: './rent-payment-validation-dialog.css',
|
||
})
|
||
export class RentPaymentValidationDialog {
|
||
readonly data = inject<RentPaymentValidationDialogData>(MAT_DIALOG_DATA);
|
||
private readonly dialogRef = inject(MatDialogRef<RentPaymentValidationDialog>);
|
||
private readonly payments = inject(RentPaymentService);
|
||
private readonly operationId = crypto.randomUUID();
|
||
readonly today = utcIsoDate();
|
||
readonly saving = signal(false);
|
||
readonly error = signal('');
|
||
readonly formatEuro = formatEuro;
|
||
|
||
readonly form = new FormGroup({
|
||
receivedAt: new FormControl(this.today, {
|
||
nonNullable: true,
|
||
validators: [Validators.required, this.notFuture.bind(this)],
|
||
}),
|
||
amount: new FormControl(this.data.rentDue.remainingAmount, {
|
||
nonNullable: true,
|
||
validators: [Validators.required, Validators.min(0.01)],
|
||
}),
|
||
});
|
||
|
||
private readonly amount = toSignal(this.form.controls.amount.valueChanges, {
|
||
initialValue: this.form.controls.amount.value,
|
||
});
|
||
readonly allocatedAmount = computed(() =>
|
||
Math.min(Math.max(this.amount() ?? 0, 0), this.data.rentDue.remainingAmount),
|
||
);
|
||
readonly remainingAfter = computed(() =>
|
||
Math.max(this.data.rentDue.remainingAmount - this.allocatedAmount(), 0),
|
||
);
|
||
readonly surplus = computed(() =>
|
||
Math.max((this.amount() ?? 0) - this.data.rentDue.remainingAmount, 0),
|
||
);
|
||
|
||
submit(): void {
|
||
this.form.markAllAsTouched();
|
||
if (this.form.invalid || this.saving()) return;
|
||
this.saving.set(true);
|
||
this.error.set('');
|
||
this.payments
|
||
.record({
|
||
operationId: this.operationId,
|
||
rentDueId: this.data.rentDue.id,
|
||
rentDueVersion: this.data.rentDue.version,
|
||
...this.form.getRawValue(),
|
||
})
|
||
.pipe(finalize(() => this.saving.set(false)))
|
||
.subscribe({
|
||
next: (payment) => this.dialogRef.close(payment),
|
||
error: (error) => {
|
||
if (isRentPaymentDataStale(error)) {
|
||
this.dialogRef.close(RENT_PAYMENT_DATA_STALE);
|
||
return;
|
||
}
|
||
this.error.set(httpErrorMessage(error, 'Impossible d’enregistrer ce règlement.'));
|
||
},
|
||
});
|
||
}
|
||
|
||
private notFuture(control: AbstractControl<string>): ValidationErrors | null {
|
||
return control.value > this.today ? { futureDate: true } : null;
|
||
}
|
||
}
|