feat: protect referenced rental resources (#27)
This commit is contained in:
1 parent
fca199dfdf
commit
971ffd6feb
23 files changed
+1453
-151
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { signal } from '@angular/core';
|
||||
import { finalize, Observable } from 'rxjs';
|
||||
import { httpErrorMessage } from './http-error-message';
|
||||
import { withoutRecordKey, withoutSetValue } from './immutable-state';
|
||||
|
||||
export interface LoadState {
|
||||
@@ -69,8 +70,11 @@ export class WorkspaceResource<T extends { id?: string }> {
|
||||
this.confirmChange((items) => items.filter((item) => item.id !== id));
|
||||
this.load();
|
||||
},
|
||||
error: () =>
|
||||
this.deleteErrors.update((errors) => ({ ...errors, [id]: this.messages.delete })),
|
||||
error: (error) =>
|
||||
this.deleteErrors.update((errors) => ({
|
||||
...errors,
|
||||
[id]: httpErrorMessage(error, this.messages.delete),
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,9 @@ describe('WorkspaceService', () => {
|
||||
leases.deleteLease.mockReturnValue(of(undefined));
|
||||
leases.downloadPdf.mockReturnValue(of(new Blob(['pdf'])));
|
||||
rentPayments.getRentPayments.mockReturnValue(of([rentPayment]));
|
||||
rentPayments.markPaid.mockReturnValue(of({ ...rentPayment, status: 'PAID', paidAt: '2026-01-02' }));
|
||||
rentPayments.markPaid.mockReturnValue(
|
||||
of({ ...rentPayment, status: 'PAID', paidAt: '2026-01-02' }),
|
||||
);
|
||||
rentPayments.downloadReceipt.mockReturnValue(of(new Blob(['receipt'])));
|
||||
dialog.open.mockImplementation(() => ({ afterClosed: () => of(true) }));
|
||||
vi.stubGlobal('URL', { createObjectURL: vi.fn(() => 'blob:test'), revokeObjectURL: vi.fn() });
|
||||
@@ -247,8 +249,10 @@ describe('WorkspaceService', () => {
|
||||
expect(service.apartmentLoadState().loading).toBe(true);
|
||||
});
|
||||
|
||||
it('preserves a record and exposes a local error when deletion fails', () => {
|
||||
apartments.deleteApartment.mockReturnValueOnce(throwError(() => new Error('offline')));
|
||||
it('preserves a referenced apartment and exposes the conflict message when deletion fails', () => {
|
||||
apartments.deleteApartment.mockReturnValueOnce(
|
||||
throwError(() => ({ error: { message: 'Cet appartement est référencé par un bail.' } })),
|
||||
);
|
||||
const service = TestBed.inject(WorkspaceService);
|
||||
service.apartments.set([apartment]);
|
||||
|
||||
@@ -257,7 +261,7 @@ describe('WorkspaceService', () => {
|
||||
expect(service.apartments()).toEqual([apartment]);
|
||||
expect(service.deletingApartmentIds().has(apartment.id)).toBe(false);
|
||||
expect(service.apartmentDeleteErrors()[apartment.id]).toBe(
|
||||
'Impossible de supprimer cet appartement.',
|
||||
'Cet appartement est référencé par un bail.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -357,7 +361,11 @@ describe('WorkspaceService', () => {
|
||||
expect(apartments.updateApartment).toHaveBeenCalledWith('apartment-1', apartment);
|
||||
expect(tenants.updateTenant).toHaveBeenCalledWith('tenant-1', tenant);
|
||||
expect(leases.deleteLease).toHaveBeenCalledWith('lease-1');
|
||||
expect(rentPayments.markPaid).toHaveBeenCalledWith('payment-1', rentPayment.rent, rentPayment.charges);
|
||||
expect(rentPayments.markPaid).toHaveBeenCalledWith(
|
||||
'payment-1',
|
||||
rentPayment.rent,
|
||||
rentPayment.charges,
|
||||
);
|
||||
});
|
||||
|
||||
it('opens a confirmation pop-in before deleting a resource', () => {
|
||||
@@ -429,7 +437,9 @@ describe('WorkspaceService', () => {
|
||||
service.downloadLeasePdf(lease);
|
||||
|
||||
await vi.waitFor(() =>
|
||||
expect(service.leaseDownloadError(lease.id)).toBe('Complétez votre profil dans les réglages.'),
|
||||
expect(service.leaseDownloadError(lease.id)).toBe(
|
||||
'Complétez votre profil dans les réglages.',
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user