diff --git a/source/backend/api/Pims.Api.csproj b/source/backend/api/Pims.Api.csproj index 7f50281d67..47167ba9fb 100644 --- a/source/backend/api/Pims.Api.csproj +++ b/source/backend/api/Pims.Api.csproj @@ -2,8 +2,8 @@ 0ef6255f-9ea0-49ec-8c65-c172304b4926 - 5.0.0-73.19 - 5.0.0-73.19 + 5.0.0-73.22 + 5.0.0-73.22 5.0.0.73 true 16BC0468-78F6-4C91-87DA-7403C919E646 diff --git a/source/backend/dal/Repositories/DispositionFileRepository.cs b/source/backend/dal/Repositories/DispositionFileRepository.cs index a629f05bd3..929fe588d4 100644 --- a/source/backend/dal/Repositories/DispositionFileRepository.cs +++ b/source/backend/dal/Repositories/DispositionFileRepository.cs @@ -184,6 +184,186 @@ public LastUpdatedByModel GetLastUpdateBy(long id) .ToList(); lastUpdatedByAggregate.AddRange(propertiesHistoryLastUpdatedBy); + // Disposition Sales + var salesLastUpdatedBy = this.Context.PimsDispositionSales.AsNoTracking() + .Where(dp => dp.DispositionFileId == id) + .Select(dp => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dp.AppLastUpdateUserid, + AppLastUpdateUserGuid = dp.AppLastUpdateUserGuid, + AppLastUpdateTimestamp = dp.AppLastUpdateTimestamp, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(salesLastUpdatedBy); + + // Disposition Deleted Sales + var salesHistoryLastUpdatedBy = Context.PimsDispositionSaleHists.AsNoTracking() + .Where(dph => dph.DispositionFileId == id) + .Select(dph => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dph.AppLastUpdateUserid, // TODO: Update this once the DB tracks the user + AppLastUpdateUserGuid = dph.AppLastUpdateUserGuid, // TODO: Update this once the DB tracks the user + AppLastUpdateTimestamp = dph.EndDateHist ?? DateTime.UnixEpoch, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(salesHistoryLastUpdatedBy); + + // Disposition Offers + var offerLastUpdatedBy = this.Context.PimsDispositionOffers.AsNoTracking() + .Where(dp => dp.DispositionFileId == id) + .Select(dp => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dp.AppLastUpdateUserid, + AppLastUpdateUserGuid = dp.AppLastUpdateUserGuid, + AppLastUpdateTimestamp = dp.AppLastUpdateTimestamp, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(offerLastUpdatedBy); + + // Disposition Deleted Offers + var offerHistoryLastUpdatedBy = Context.PimsDispositionOfferHists.AsNoTracking() + .Where(dph => dph.DispositionFileId == id) + .Select(dph => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dph.AppLastUpdateUserid, // TODO: Update this once the DB tracks the user + AppLastUpdateUserGuid = dph.AppLastUpdateUserGuid, // TODO: Update this once the DB tracks the user + AppLastUpdateTimestamp = dph.EndDateHist ?? DateTime.UnixEpoch, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(offerHistoryLastUpdatedBy); + + // Disposition Values + var valueLastUpdatedBy = this.Context.PimsDispositionAppraisals.AsNoTracking() + .Where(dp => dp.DispositionFileId == id) + .Select(dp => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dp.AppLastUpdateUserid, + AppLastUpdateUserGuid = dp.AppLastUpdateUserGuid, + AppLastUpdateTimestamp = dp.AppLastUpdateTimestamp, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(valueLastUpdatedBy); + + // Disposition Deleted Values + var valueHistoryLastUpdatedBy = Context.PimsDispositionAppraisalHists.AsNoTracking() + .Where(dph => dph.DispositionFileId == id) + .Select(dph => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dph.AppLastUpdateUserid, // TODO: Update this once the DB tracks the user + AppLastUpdateUserGuid = dph.AppLastUpdateUserGuid, // TODO: Update this once the DB tracks the user + AppLastUpdateTimestamp = dph.EndDateHist ?? DateTime.UnixEpoch, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(valueHistoryLastUpdatedBy); + + // Disposition Checklist + var checklistLastUpdatedBy = this.Context.PimsDispositionChecklistItems.AsNoTracking() + .Where(dp => dp.DispositionFileId == id) + .Select(dp => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dp.AppLastUpdateUserid, + AppLastUpdateUserGuid = dp.AppLastUpdateUserGuid, + AppLastUpdateTimestamp = dp.AppLastUpdateTimestamp, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(checklistLastUpdatedBy); + + // Disposition Deleted Checklists + var checklistHistoryLastUpdatedBy = Context.PimsDispositionChecklistItemHists.AsNoTracking() + .Where(dph => dph.DispositionFileId == id) + .Select(dph => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dph.AppLastUpdateUserid, // TODO: Update this once the DB tracks the user + AppLastUpdateUserGuid = dph.AppLastUpdateUserGuid, // TODO: Update this once the DB tracks the user + AppLastUpdateTimestamp = dph.EndDateHist ?? DateTime.UnixEpoch, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(checklistHistoryLastUpdatedBy); + + // Disposition Document + var documentLastUpdatedBy = this.Context.PimsDispositionFileDocuments.AsNoTracking() + .Where(dp => dp.DispositionFileId == id) + .Select(dp => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dp.AppLastUpdateUserid, + AppLastUpdateUserGuid = dp.AppLastUpdateUserGuid, + AppLastUpdateTimestamp = dp.AppLastUpdateTimestamp, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(documentLastUpdatedBy); + + // Disposition Deleted Documents + var documentHistoryLastUpdatedBy = Context.PimsDispositionFileDocumentHists.AsNoTracking() + .Where(dph => dph.DispositionFileId == id) + .Select(dph => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dph.AppLastUpdateUserid, // TODO: Update this once the DB tracks the user + AppLastUpdateUserGuid = dph.AppLastUpdateUserGuid, // TODO: Update this once the DB tracks the user + AppLastUpdateTimestamp = dph.EndDateHist ?? DateTime.UnixEpoch, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(documentHistoryLastUpdatedBy); + + // Disposition Notes + var notesLastUpdatedBy = this.Context.PimsDispositionFileNotes.AsNoTracking() + .Where(dp => dp.DispositionFileId == id) + .Select(dp => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dp.AppLastUpdateUserid, + AppLastUpdateUserGuid = dp.AppLastUpdateUserGuid, + AppLastUpdateTimestamp = dp.AppLastUpdateTimestamp, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(notesLastUpdatedBy); + + // Disposition Deleted Notes + var notesHistoryLastUpdatedBy = Context.PimsDispositionFileNoteHists.AsNoTracking() + .Where(dph => dph.DispositionFileId == id) + .Select(dph => new LastUpdatedByModel() + { + ParentId = id, + AppLastUpdateUserid = dph.AppLastUpdateUserid, // TODO: Update this once the DB tracks the user + AppLastUpdateUserGuid = dph.AppLastUpdateUserGuid, // TODO: Update this once the DB tracks the user + AppLastUpdateTimestamp = dph.EndDateHist ?? DateTime.UnixEpoch, + }) + .OrderByDescending(lu => lu.AppLastUpdateTimestamp) + .Take(1) + .ToList(); + lastUpdatedByAggregate.AddRange(notesHistoryLastUpdatedBy); + return lastUpdatedByAggregate.OrderByDescending(x => x.AppLastUpdateTimestamp).FirstOrDefault(); } diff --git a/source/frontend/package.json b/source/frontend/package.json index 9d52a60bf8..67bd062a36 100644 --- a/source/frontend/package.json +++ b/source/frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "5.0.0-73.19", + "version": "5.0.0-73.22", "private": true, "dependencies": { "@bcgov/bc-sans": "1.0.1", diff --git a/source/frontend/public/mockServiceWorker.js b/source/frontend/public/mockServiceWorker.js index a8aa7b555f..4147a4044c 100644 --- a/source/frontend/public/mockServiceWorker.js +++ b/source/frontend/public/mockServiceWorker.js @@ -8,121 +8,121 @@ * - Please do NOT serve this file on production. */ -const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70' -const activeClientIds = new Set() +const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70'; +const activeClientIds = new Set(); self.addEventListener('install', function () { - self.skipWaiting() -}) + self.skipWaiting(); +}); self.addEventListener('activate', function (event) { - event.waitUntil(self.clients.claim()) -}) + event.waitUntil(self.clients.claim()); +}); self.addEventListener('message', async function (event) { - const clientId = event.source.id + const clientId = event.source.id; if (!clientId || !self.clients) { - return + return; } - const client = await self.clients.get(clientId) + const client = await self.clients.get(clientId); if (!client) { - return + return; } const allClients = await self.clients.matchAll({ type: 'window', - }) + }); switch (event.data) { case 'KEEPALIVE_REQUEST': { sendToClient(client, { type: 'KEEPALIVE_RESPONSE', - }) - break + }); + break; } case 'INTEGRITY_CHECK_REQUEST': { sendToClient(client, { type: 'INTEGRITY_CHECK_RESPONSE', payload: INTEGRITY_CHECKSUM, - }) - break + }); + break; } case 'MOCK_ACTIVATE': { - activeClientIds.add(clientId) + activeClientIds.add(clientId); sendToClient(client, { type: 'MOCKING_ENABLED', payload: true, - }) - break + }); + break; } case 'MOCK_DEACTIVATE': { - activeClientIds.delete(clientId) - break + activeClientIds.delete(clientId); + break; } case 'CLIENT_CLOSED': { - activeClientIds.delete(clientId) + activeClientIds.delete(clientId); - const remainingClients = allClients.filter((client) => { - return client.id !== clientId - }) + const remainingClients = allClients.filter(client => { + return client.id !== clientId; + }); // Unregister itself when there are no more clients if (remainingClients.length === 0) { - self.registration.unregister() + self.registration.unregister(); } - break + break; } } -}) +}); self.addEventListener('fetch', function (event) { - const { request } = event - const accept = request.headers.get('accept') || '' + const { request } = event; + const accept = request.headers.get('accept') || ''; // Bypass server-sent events. if (accept.includes('text/event-stream')) { - return + return; } // Bypass navigation requests. if (request.mode === 'navigate') { - return + return; } // Opening the DevTools triggers the "only-if-cached" request // that cannot be handled by the worker. Bypass such requests. if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { - return + return; } // Bypass all requests when there are no active clients. // Prevents the self-unregistered worked from handling requests // after it's been deleted (still remains active until the next reload). if (activeClientIds.size === 0) { - return + return; } // Generate unique request ID. - const requestId = Math.random().toString(16).slice(2) + const requestId = Math.random().toString(16).slice(2); event.respondWith( - handleRequest(event, requestId).catch((error) => { + handleRequest(event, requestId).catch(error => { if (error.name === 'NetworkError') { console.warn( '[MSW] Successfully emulated a network error for the "%s %s" request.', request.method, request.url, - ) - return + ); + return; } // At this point, any exception indicates an issue with the original request/response. @@ -132,21 +132,21 @@ self.addEventListener('fetch', function (event) { request.method, request.url, `${error.name}: ${error.message}`, - ) + ); }), - ) -}) + ); +}); async function handleRequest(event, requestId) { - const client = await resolveMainClient(event) - const response = await getResponse(event, client, requestId) + const client = await resolveMainClient(event); + const response = await getResponse(event, client, requestId); // Send back the response clone for the "response:*" life-cycle events. // Ensure MSW is active and ready to handle the message, otherwise // this message will pend indefinitely. if (client && activeClientIds.has(client.id)) { - ;(async function () { - const clonedResponse = response.clone() + (async function () { + const clonedResponse = response.clone(); sendToClient(client, { type: 'RESPONSE', payload: { @@ -155,16 +155,15 @@ async function handleRequest(event, requestId) { ok: clonedResponse.ok, status: clonedResponse.status, statusText: clonedResponse.statusText, - body: - clonedResponse.body === null ? null : await clonedResponse.text(), + body: clonedResponse.body === null ? null : await clonedResponse.text(), headers: Object.fromEntries(clonedResponse.headers.entries()), redirected: clonedResponse.redirected, }, - }) - })() + }); + })(); } - return response + return response; } // Resolve the main client for the given event. @@ -172,49 +171,49 @@ async function handleRequest(event, requestId) { // that registered the worker. It's with the latter the worker should // communicate with during the response resolving phase. async function resolveMainClient(event) { - const client = await self.clients.get(event.clientId) + const client = await self.clients.get(event.clientId); if (client?.frameType === 'top-level') { - return client + return client; } const allClients = await self.clients.matchAll({ type: 'window', - }) + }); return allClients - .filter((client) => { + .filter(client => { // Get only those clients that are currently visible. - return client.visibilityState === 'visible' + return client.visibilityState === 'visible'; }) - .find((client) => { + .find(client => { // Find the client ID that's recorded in the // set of clients that have registered the worker. - return activeClientIds.has(client.id) - }) + return activeClientIds.has(client.id); + }); } async function getResponse(event, client, requestId) { - const { request } = event - const clonedRequest = request.clone() + const { request } = event; + const clonedRequest = request.clone(); function passthrough() { // Clone the request because it might've been already used // (i.e. its body has been read and sent to the client). - const headers = Object.fromEntries(clonedRequest.headers.entries()) + const headers = Object.fromEntries(clonedRequest.headers.entries()); // Remove MSW-specific request headers so the bypassed requests // comply with the server's CORS preflight check. // Operate with the headers as an object because request "Headers" // are immutable. - delete headers['x-msw-bypass'] + delete headers['x-msw-bypass']; - return fetch(clonedRequest, { headers }) + return fetch(clonedRequest, { headers }); } // Bypass mocking when the client is not active. if (!client) { - return passthrough() + return passthrough(); } // Bypass initial page load requests (i.e. static assets). @@ -222,13 +221,13 @@ async function getResponse(event, client, requestId) { // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet // and is not ready to handle requests. if (!activeClientIds.has(client.id)) { - return passthrough() + return passthrough(); } // Bypass requests with the explicit bypass header. // Such requests can be issued by "ctx.fetch()". if (request.headers.get('x-msw-bypass') === 'true') { - return passthrough() + return passthrough(); } // Notify the client that a request has been intercepted. @@ -251,53 +250,53 @@ async function getResponse(event, client, requestId) { bodyUsed: request.bodyUsed, keepalive: request.keepalive, }, - }) + }); switch (clientMessage.type) { case 'MOCK_RESPONSE': { - return respondWithMock(clientMessage.data) + return respondWithMock(clientMessage.data); } case 'MOCK_NOT_FOUND': { - return passthrough() + return passthrough(); } case 'NETWORK_ERROR': { - const { name, message } = clientMessage.data - const networkError = new Error(message) - networkError.name = name + const { name, message } = clientMessage.data; + const networkError = new Error(message); + networkError.name = name; // Rejecting a "respondWith" promise emulates a network error. - throw networkError + throw networkError; } } - return passthrough() + return passthrough(); } function sendToClient(client, message) { return new Promise((resolve, reject) => { - const channel = new MessageChannel() + const channel = new MessageChannel(); - channel.port1.onmessage = (event) => { + channel.port1.onmessage = event => { if (event.data && event.data.error) { - return reject(event.data.error) + return reject(event.data.error); } - resolve(event.data) - } + resolve(event.data); + }; - client.postMessage(message, [channel.port2]) - }) + client.postMessage(message, [channel.port2]); + }); } function sleep(timeMs) { - return new Promise((resolve) => { - setTimeout(resolve, timeMs) - }) + return new Promise(resolve => { + setTimeout(resolve, timeMs); + }); } async function respondWithMock(response) { - await sleep(response.delay) - return new Response(response.body, response) + await sleep(response.delay); + return new Response(response.body, response); } diff --git a/source/frontend/src/components/Table/Table.tsx b/source/frontend/src/components/Table/Table.tsx index 7ff83eb146..6ee55677a4 100644 --- a/source/frontend/src/components/Table/Table.tsx +++ b/source/frontend/src/components/Table/Table.tsx @@ -343,6 +343,7 @@ export const Table = ( manualSortBy: manualSortBy, pageCount, autoResetSelectedRows: false, + autoResetPage: false, }, useFlexLayout, useSortBy, diff --git a/source/frontend/src/constants/dispositionFileStatus.ts b/source/frontend/src/constants/dispositionFileStatus.ts new file mode 100644 index 0000000000..c38da04834 --- /dev/null +++ b/source/frontend/src/constants/dispositionFileStatus.ts @@ -0,0 +1,9 @@ +export enum DispositionFileStatus { + Active = 'ACTIVE', + Archived = 'ARCHIVED', + Cancelled = 'CANCELLED', + Closed = 'CLOSED', + Complete = 'COMPLETE', + Draft = 'DRAFT', + Hold = 'HOLD', +} diff --git a/source/frontend/src/features/mapSideBar/disposition/DispositionContainer.test.tsx b/source/frontend/src/features/mapSideBar/disposition/DispositionContainer.test.tsx index 0a15fa17b4..57502bdddd 100644 --- a/source/frontend/src/features/mapSideBar/disposition/DispositionContainer.test.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/DispositionContainer.test.tsx @@ -238,7 +238,7 @@ describe('DispositionContainer component', () => { const spinner = getByTestId('filter-backdrop-loading'); await waitForElementToBeRemoved(spinner); - await act(async () => viewProps.onSuccess()); + await act(async () => viewProps.onSuccess(true, true)); expect(mockAxios.history.get.filter(x => x.url === '/dispositionfiles/1')).toHaveLength(2); }); diff --git a/source/frontend/src/features/mapSideBar/disposition/DispositionContainer.tsx b/source/frontend/src/features/mapSideBar/disposition/DispositionContainer.tsx index 01bfddc66f..6155f63836 100644 --- a/source/frontend/src/features/mapSideBar/disposition/DispositionContainer.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/DispositionContainer.tsx @@ -198,10 +198,12 @@ export const DispositionContainer: React.FunctionComponent { - fetchDispositionFile(); + const onSuccess = (refreshProperties?: boolean, refreshFile?: boolean) => { setIsEditing(false); fetchLastUpdatedBy(); + if (refreshFile) { + fetchDispositionFile(); + } if (refreshProperties) { mapMachine.refreshMapProperties(); } diff --git a/source/frontend/src/features/mapSideBar/disposition/DispositionView.tsx b/source/frontend/src/features/mapSideBar/disposition/DispositionView.tsx index 2a3436100a..262091faef 100644 --- a/source/frontend/src/features/mapSideBar/disposition/DispositionView.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/DispositionView.tsx @@ -38,7 +38,7 @@ export interface IDispositionViewProps { onCancel: () => void; onMenuChange: (selectedIndex: number) => void; onShowPropertySelector: () => void; - onSuccess: (updateProperties?: boolean) => void; + onSuccess: (updateProperties?: boolean, updateFile?: boolean) => void; onUpdateProperties: (file: Api_File) => Promise; canRemove: (propertyId: number) => Promise; isEditing: boolean; diff --git a/source/frontend/src/features/mapSideBar/disposition/router/DispositionRouter.tsx b/source/frontend/src/features/mapSideBar/disposition/router/DispositionRouter.tsx index c9991118f0..0c20aab1dd 100644 --- a/source/frontend/src/features/mapSideBar/disposition/router/DispositionRouter.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/router/DispositionRouter.tsx @@ -29,7 +29,7 @@ export interface IDispositionRouterProps { setIsEditing: (value: boolean) => void; defaultFileTab: FileTabType; defaultPropertyTab: InventoryTabNames; - onSuccess: (updateProperties?: boolean) => void; + onSuccess: (updateProperties?: boolean, updateFile?: boolean) => void; } export const DispositionRouter: React.FC = props => { @@ -84,6 +84,7 @@ export const DispositionRouter: React.FC = props => { )} claim={Claims.DISPOSITION_EDIT} @@ -97,6 +98,7 @@ export const DispositionRouter: React.FC = props => { )} claim={Claims.DISPOSITION_EDIT} @@ -111,6 +113,7 @@ export const DispositionRouter: React.FC = props => { dispositionFileId={props.dispositionFile?.id ?? 0} dispositionOfferId={match.params.offerId} View={DispositionOfferForm} + onSuccess={props.onSuccess} > )} claim={Claims.DISPOSITION_EDIT} diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/DispositionFileTabs.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/DispositionFileTabs.tsx index 28c5c5df8f..e969a6724c 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/DispositionFileTabs.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/DispositionFileTabs.tsx @@ -59,6 +59,7 @@ export const DispositionFileTabs: React.FC = ({ ), key: FileTabType.OFFERS_AND_SALE, diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/fileDetails/detail/update/UpdateDispositionContainer.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/fileDetails/detail/update/UpdateDispositionContainer.tsx index 93a9604340..55a44f180a 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/fileDetails/detail/update/UpdateDispositionContainer.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/fileDetails/detail/update/UpdateDispositionContainer.tsx @@ -3,6 +3,7 @@ import { FormikHelpers, FormikProps } from 'formik'; import React from 'react'; import { ModalSize } from '@/components/common/GenericModal'; +import { DispositionFileStatus } from '@/constants/dispositionFileStatus'; import { useDispositionProvider } from '@/hooks/repositories/useDispositionProvider'; import useApiUserOverride from '@/hooks/useApiUserOverride'; import { useModalContext } from '@/hooks/useModalContext'; @@ -15,7 +16,7 @@ import { IUpdateDispositionFormProps } from './UpdateDispositionForm'; export interface IUpdateDispositionContainerProps { dispositionFile: Api_DispositionFile; - onSuccess: () => void; + onSuccess: (updateProperties?: boolean, updateFile?: boolean) => void; View: React.FC; } @@ -50,7 +51,17 @@ export const UpdateDispositionContainer = React.forwardRef< if (!!response?.id) { formikHelpers?.resetForm(); - onSuccess(); + const activeTypeCodes = [ + DispositionFileStatus.Active.toString(), + DispositionFileStatus.Draft.toString(), + DispositionFileStatus.Hold.toString(), + ]; + //refresh the map properties if this disposition file was set to a final state. + onSuccess( + !!dispositionFile.fileStatusTypeCode?.id && + !activeTypeCodes.includes(dispositionFile.fileStatusTypeCode.id), + true, + ); } } } finally { diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/OffersAndSaleContainer.test.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/OffersAndSaleContainer.test.tsx index 0fcb051a90..c9cc2e63af 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/OffersAndSaleContainer.test.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/OffersAndSaleContainer.test.tsx @@ -40,7 +40,7 @@ const mockDeleteDispositionFileOfferApi = { loading: false, }; -const mockGetDispositionFileApi = mockDispositionFileResponse(1) as unknown as Api_DispositionFile; +const onSuccess = jest.fn(); jest.mock('@/hooks/repositories/useDispositionProvider', () => ({ useDispositionProvider: () => { @@ -68,8 +68,12 @@ describe('OffersAndSale Container component', () => { ) => { const component = render( , { history, diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/OffersAndSaleContainer.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/OffersAndSaleContainer.tsx index d0bbd38930..621dbb5fc9 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/OffersAndSaleContainer.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/OffersAndSaleContainer.tsx @@ -13,11 +13,13 @@ import { IOffersAndSaleContainerViewProps } from './OffersAndSaleContainerView'; export interface IOffersAndSaleContainerProps { dispositionFile?: Api_DispositionFile; View: React.FC; + onSuccess: () => void; } const OffersAndSaleContainer: React.FunctionComponent = ({ dispositionFile, View, + onSuccess, }) => { const { getDispositionFileOffers: { execute: getDispositionFileOffers, loading: loadingOffers }, @@ -67,6 +69,7 @@ const OffersAndSaleContainer: React.FunctionComponent ({ useDispositionProvider: () => { return { @@ -62,7 +64,11 @@ describe('Update Disposition Appraisal Container component', () => { } = {}, ) => { const component = render( - , + , { history, store: { diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionAppraisal/update/UpdateDispositionAppraisalContainer.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionAppraisal/update/UpdateDispositionAppraisalContainer.tsx index f05d5d285b..a3a29ac0e8 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionAppraisal/update/UpdateDispositionAppraisalContainer.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionAppraisal/update/UpdateDispositionAppraisalContainer.tsx @@ -13,11 +13,12 @@ import { IDispositionAppraisalFormProps } from '../form/DispositionAppraisalForm export interface IUpdateDispositionAppraisalContainerProps { dispositionFileId: number; View: React.FC; + onSuccess: () => void; } const UpdateDispositionAppraisalContainer: React.FunctionComponent< React.PropsWithChildren -> = ({ dispositionFileId, View }) => { +> = ({ dispositionFileId, View, onSuccess }) => { const history = useHistory(); const location = useLocation(); const backUrl = location.pathname.split(`/appraisal`)[0]; @@ -51,7 +52,8 @@ const UpdateDispositionAppraisalContainer: React.FunctionComponent< } }; - const handleSucces = async () => { + const handleSuccess = async () => { + onSuccess(); history.push(backUrl); }; @@ -73,7 +75,7 @@ const UpdateDispositionAppraisalContainer: React.FunctionComponent< initialValues={dispositionAppraisal} loading={loadingAppraisal || creatingAppraisal || updatingAppraisal} onSave={handleSave} - onSuccess={handleSucces} + onSuccess={handleSuccess} onCancel={() => history.push(backUrl)} onError={onError} > diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/add/AddDispositionOfferContainer.test.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/add/AddDispositionOfferContainer.test.tsx index 87341779d1..827702b1e8 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/add/AddDispositionOfferContainer.test.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/add/AddDispositionOfferContainer.test.tsx @@ -21,6 +21,7 @@ const mockPostApi = { execute: jest.fn(), loading: false, }; +const onSuccess = jest.fn(); jest.mock('@/hooks/repositories/useDispositionProvider', () => ({ useDispositionProvider: () => { @@ -44,7 +45,7 @@ describe('Add Disposition Offer Container component', () => { } = {}, ) => { const component = render( - , + , { history, store: { diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/add/AddDispositionOfferContainer.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/add/AddDispositionOfferContainer.tsx index 905fdd0041..62ce7ed179 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/add/AddDispositionOfferContainer.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/add/AddDispositionOfferContainer.tsx @@ -14,11 +14,12 @@ import { DispositionOfferFormModel } from '../models/DispositionOfferFormModel'; export interface IAddDispositionOfferContainerProps { dispositionFileId: number; View: React.FC; + onSuccess: () => void; } const AddDispositionOfferContainer: React.FunctionComponent< React.PropsWithChildren -> = ({ dispositionFileId, View }) => { +> = ({ dispositionFileId, View, onSuccess }) => { const history = useHistory(); const location = useLocation(); @@ -37,6 +38,7 @@ const AddDispositionOfferContainer: React.FunctionComponent< }; const handleSuccess = async () => { + onSuccess(); history.push(backUrl); }; diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/update/UpdateDispositionOfferContainer.test.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/update/UpdateDispositionOfferContainer.test.tsx index f58bc7ff78..826b684a6a 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/update/UpdateDispositionOfferContainer.test.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/update/UpdateDispositionOfferContainer.test.tsx @@ -30,6 +30,7 @@ const mockGetOfferApi = { execute: jest.fn().mockResolvedValue(mockDispositionOfferApi), loading: false, }; +const onSuccess = jest.fn(); jest.mock('@/hooks/repositories/useDispositionProvider', () => ({ useDispositionProvider: () => { @@ -58,6 +59,7 @@ describe('Update Disposition Offer Container component', () => { dispositionFileId={1} dispositionOfferId={10} View={TestView} + onSuccess={onSuccess} />, { history, diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/update/UpdateDispositionOfferContainer.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/update/UpdateDispositionOfferContainer.tsx index 611a707c53..59383dad13 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/update/UpdateDispositionOfferContainer.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionOffer/update/UpdateDispositionOfferContainer.tsx @@ -15,11 +15,12 @@ export interface IUpdateDispositionOfferContainerProps { dispositionFileId: number; dispositionOfferId: number; View: React.FC; + onSuccess: () => void; } const UpdateDispositionOfferContainer: React.FunctionComponent< React.PropsWithChildren -> = ({ dispositionFileId, dispositionOfferId, View }) => { +> = ({ dispositionFileId, dispositionOfferId, View, onSuccess }) => { const history = useHistory(); const location = useLocation(); const backUrl = location.pathname.split(`/offers/${dispositionOfferId}/update`)[0]; @@ -47,6 +48,7 @@ const UpdateDispositionOfferContainer: React.FunctionComponent< }; const handleSucces = async () => { + onSuccess(); history.push(backUrl); }; diff --git a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionSale/update/UpdateDispositionSaleContainer.tsx b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionSale/update/UpdateDispositionSaleContainer.tsx index a3d6ea0407..a12f8dd3c2 100644 --- a/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionSale/update/UpdateDispositionSaleContainer.tsx +++ b/source/frontend/src/features/mapSideBar/disposition/tabs/offersAndSale/dispositionSale/update/UpdateDispositionSaleContainer.tsx @@ -1,8 +1,9 @@ import { AxiosError } from 'axios'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useContext, useEffect, useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { toast } from 'react-toastify'; +import { SideBarContext } from '@/features/mapSideBar/context/sidebarContext'; import { DispositionSaleFormModel } from '@/features/mapSideBar/disposition/models/DispositionSaleFormModel'; import { useDispositionProvider } from '@/hooks/repositories/useDispositionProvider'; import { IApiError } from '@/interfaces/IApiError'; @@ -21,6 +22,7 @@ const UpdateDispositionSaleContainer: React.FunctionComponent< const history = useHistory(); const location = useLocation(); const backUrl = location.pathname.split(`/sale/update`)[0]; + const { setStaleLastUpdatedBy } = useContext(SideBarContext); const initialValues = new DispositionSaleFormModel(null, dispositionFileId, null); const [dispositionSale, setDispositionSale] = useState(initialValues); @@ -51,6 +53,7 @@ const UpdateDispositionSaleContainer: React.FunctionComponent< const handleSucces = async () => { history.push(backUrl); + setStaleLastUpdatedBy(true); }; const handleSave = async (dispositionSale: ApiGen_Concepts_DispositionFileSale) => { diff --git a/source/frontend/src/features/mapSideBar/shared/update/properties/UpdateProperties.tsx b/source/frontend/src/features/mapSideBar/shared/update/properties/UpdateProperties.tsx index 01a11679f8..bfed0d7b67 100644 --- a/source/frontend/src/features/mapSideBar/shared/update/properties/UpdateProperties.tsx +++ b/source/frontend/src/features/mapSideBar/shared/update/properties/UpdateProperties.tsx @@ -25,7 +25,7 @@ import { UpdatePropertiesYupSchema } from './UpdatePropertiesYupSchema'; export interface IUpdatePropertiesProps { file: Api_File; setIsShowingPropertySelector: (isShowing: boolean) => void; - onSuccess: () => void; + onSuccess: (refreshProperties?: boolean) => void; updateFileProperties: ( file: Api_File, userOverrideCodes: UserOverrideCode[], @@ -109,7 +109,7 @@ export const UpdateProperties: React.FunctionComponent< } formikRef.current?.resetForm(); props.setIsShowingPropertySelector(false); - props.onSuccess(); + props.onSuccess(true); } } catch (e) { if (axios.isAxiosError(e) && (e as AxiosError).code === '409') { diff --git a/testing/PIMS.Tests.Automation/Classes/DispositionFile.cs b/testing/PIMS.Tests.Automation/Classes/DispositionFile.cs index abad65f789..47c5ad985d 100644 --- a/testing/PIMS.Tests.Automation/Classes/DispositionFile.cs +++ b/testing/PIMS.Tests.Automation/Classes/DispositionFile.cs @@ -14,7 +14,7 @@ public class DispositionFile public string InitiatingDocument { get; set; } = null!; public string OtherInitiatingDocument { get; set; } = null!; public string InitiatingDocumentDate { get; set; } = null!; - public string PhysicalFileStatus { get; set; } = null!; + public string DispositionPhysicalFileStatus { get; set; } = null!; public string InitiatingBranch { get; set; } = null!; public string DispositionMOTIRegion { get; set; } = null!; public int DispositionTeamStartRow { get; set; } = 0; @@ -36,16 +36,23 @@ public class DispositionFile public int PurchaseNameTotalCount { get; set; } = 0; public List PurchaserNames { get; set; } = new List(); public string PurchaserAgent { get; set; } = null!; + public string PurchaserAgentType { get; set; } = null!; + public string PurchaserAgentPrimaryContact { get; set; } = null!; public string PurchaserSolicitor { get; set; } = null!; + public string PurchaserSolicitorType { get; set; } = null!; + public string PurchaserSolicitorPrimaryContact { get; set; } = null!; public string LastConditionRemovalDate { get; set; } = null!; public string SaleCompletionDate { get; set; } = null!; public string FiscalYearOfSale { get; set; } = null!; public string FinalSalePrice { get; set; } = null!; public string RealtorCommission { get; set; } = null!; public string GSTRequired { get; set; } = null!; + public string GSTCollected { get; set; } = null!; public string NetBookValue { get; set; } = null!; public string TotalCostOfSales { get; set; } = null!; + public string NetProceedsBeforeSPP { get; set; } = null!; public string SPPAmount { get; set; } = null!; + public string NetProceedsAfterSPP { get; set; } = null!; public string RemediationCost { get; set; } = null!; } diff --git a/testing/PIMS.Tests.Automation/Data/PIMS_Testing_Data.xlsx b/testing/PIMS.Tests.Automation/Data/PIMS_Testing_Data.xlsx index 0dc7b2406e..af064dfee1 100644 Binary files a/testing/PIMS.Tests.Automation/Data/PIMS_Testing_Data.xlsx and b/testing/PIMS.Tests.Automation/Data/PIMS_Testing_Data.xlsx differ diff --git a/testing/PIMS.Tests.Automation/PageObjects/AcquisitionDetails.cs b/testing/PIMS.Tests.Automation/PageObjects/AcquisitionDetails.cs index 7c50509dfb..40e55a257b 100644 --- a/testing/PIMS.Tests.Automation/PageObjects/AcquisitionDetails.cs +++ b/testing/PIMS.Tests.Automation/PageObjects/AcquisitionDetails.cs @@ -605,8 +605,8 @@ public void VerifyAcquisitionFileView(AcquisitionFile acquisition) AssertTrueElementContains(By.XPath("//span[@data-testid='owner["+ i +"]']/div[4]/div[2]"), acquisition.AcquisitionOwners[i].MailCity); if (acquisition.AcquisitionOwners[i].MailProvince != "") AssertTrueElementContains(By.XPath("//span[@data-testid='owner["+ i +"]']/div[4]/div[2]"), acquisition.AcquisitionOwners[i].MailProvince); - //if (acquisition.AcquisitionOwners[i].MailOtherCountry != "") - //AssertTrueElementContains(By.XPath("//span[@data-testid='owner["+ i +"]']/div[4]/div[2]"), acquisition.AcquisitionOwners[i].MailOtherCountry); + if (acquisition.AcquisitionOwners[i].MailOtherCountry != "") + AssertTrueElementContains(By.XPath("//span[@data-testid='owner["+ i +"]']/div[4]/div[2]"), "Other - " + acquisition.AcquisitionOwners[i].MailOtherCountry); if (acquisition.AcquisitionOwners[i].MailPostalCode != "") AssertTrueElementContains(By.XPath("//span[@data-testid='owner["+ i +"]']/div[4]/div[2]"), acquisition.AcquisitionOwners[i].MailPostalCode); } diff --git a/testing/PIMS.Tests.Automation/PageObjects/AcquisitionTakes.cs b/testing/PIMS.Tests.Automation/PageObjects/AcquisitionTakes.cs index 4e685a1baf..c3e9bc4c08 100644 --- a/testing/PIMS.Tests.Automation/PageObjects/AcquisitionTakes.cs +++ b/testing/PIMS.Tests.Automation/PageObjects/AcquisitionTakes.cs @@ -299,7 +299,7 @@ public void VerifyInitCreateForm() public void VerifyCreatedTakeViewForm(Take take) { - var index = 0; + var index = take.TakeCounter; //Take Details AssertTrueIsDisplayed(By.XPath("//div[@data-testid='take-"+ index +"']/div/div/div/label[contains(text(),'Take added on')]")); diff --git a/testing/PIMS.Tests.Automation/PageObjects/DispositionFileDetails.cs b/testing/PIMS.Tests.Automation/PageObjects/DispositionFileDetails.cs index 37a7ec32e0..d38caf5a73 100644 --- a/testing/PIMS.Tests.Automation/PageObjects/DispositionFileDetails.cs +++ b/testing/PIMS.Tests.Automation/PageObjects/DispositionFileDetails.cs @@ -259,8 +259,8 @@ public void AddAdditionalInformation(DispositionFile disposition) webDriver.FindElement(dispositionFileDetailsInitiatingDocumentDateInput).SendKeys(Keys.Enter); } - if (disposition.PhysicalFileStatus != "") - ChooseSpecificSelectOption(dispositionFileDetailsPhysicalFileSelect, disposition.PhysicalFileStatus); + if (disposition.DispositionPhysicalFileStatus != "") + ChooseSpecificSelectOption(dispositionFileDetailsPhysicalFileSelect, disposition.DispositionPhysicalFileStatus); if (disposition.InitiatingBranch != "") ChooseSpecificSelectOption(dispositionFileDetailsInitiatingBranchSelect, disposition.InitiatingBranch); @@ -343,8 +343,8 @@ public void UpdateDispositionFile(DispositionFile disposition) webDriver.FindElement(dispositionFileDetailsInitiatingDocumentDateInput).SendKeys(Keys.Enter); } - if (disposition.PhysicalFileStatus != "") - ChooseSpecificSelectOption(dispositionFileDetailsPhysicalFileSelect, disposition.PhysicalFileStatus); + if (disposition.DispositionPhysicalFileStatus != "") + ChooseSpecificSelectOption(dispositionFileDetailsPhysicalFileSelect, disposition.DispositionPhysicalFileStatus); if (disposition.InitiatingBranch != "") ChooseSpecificSelectOption(dispositionFileDetailsInitiatingBranchSelect, disposition.InitiatingBranch); @@ -569,8 +569,8 @@ public void VerifyDispositionFileView(DispositionFile disposition) //Physical File Status AssertTrueIsDisplayed(dispositionFileDetailsPhysicalFileLabel); - if (disposition.PhysicalFileStatus != "") - AssertTrueContentEquals(dispositionFileDetailsPhysicalFileContent, disposition.PhysicalFileStatus); + if (disposition.DispositionPhysicalFileStatus != "") + AssertTrueContentEquals(dispositionFileDetailsPhysicalFileContent, disposition.DispositionPhysicalFileStatus); //Initiating Branch //AssertTrueIsDisplayed(dispositionFileDetailsInitiatingBranchLabel); diff --git a/testing/PIMS.Tests.Automation/PageObjects/DispositionOfferSale.cs b/testing/PIMS.Tests.Automation/PageObjects/DispositionOfferSale.cs index 8fee1f997d..91060bba11 100644 --- a/testing/PIMS.Tests.Automation/PageObjects/DispositionOfferSale.cs +++ b/testing/PIMS.Tests.Automation/PageObjects/DispositionOfferSale.cs @@ -1,6 +1,5 @@ using OpenQA.Selenium; using PIMS.Tests.Automation.Classes; -using System; namespace PIMS.Tests.Automation.PageObjects { @@ -12,6 +11,8 @@ public class DispositionOfferSale : PageObjectBase private By offersAndSaleAppraisalAndAssessmentSubtitle = By.XPath("//h2/div/div/div/label[contains(text(), 'Appraisal and Assessment')]"); private By dispositionAppraisalEditButton = By.CssSelector("button[title='Edit Appraisal']"); private By dispositionAppraisalAndAssessmentMessage = By.XPath("//p[contains(text(),'There are no Appraisal and Assessment details indicated with this disposition file.')]"); + + private By dispositionAppraisalAndAssessmentCreateFormSubtitle = By.XPath("//h2/div/div[contains(text(), 'Appraisal and Assessment')]"); private By dispositionAppraisalValueLabel = By.XPath("//label[contains(text(),'Appraisal value ($)')]"); private By dispositionAppraisalValueContent = By.XPath("//label[contains(text(),'Appraisal value ($)')]/parent::div/following-sibling::div"); private By dispositionAppraisalValueInput = By.Id("input-appraisedValueAmount"); @@ -33,6 +34,7 @@ public class DispositionOfferSale : PageObjectBase private By addOffersButton = By.XPath("//div[contains(text(),'Offers')]/following-sibling::div/button"); private By dispositionOffersMessage = By.XPath("//p[contains(text(),'There are no offers indicated with this disposition file.')]"); + private By dispositionOfferCreateSubtitle = By.XPath("//div[contains(text(),'Offer')]"); private By dispositionOfferStatusLabel = By.XPath("//label[contains(text(),'Offer status')]"); private By dispositionOfferStatusSelect = By.Id("input-dispositionOfferStatusTypeCode"); private By dispositionOfferStatusTooltip = By.XPath("//label[contains(text(),'Offer status')]/span/span[@data-testid='tooltip-icon-section-field-tooltip']"); @@ -53,52 +55,75 @@ public class DispositionOfferSale : PageObjectBase private By dispositionSalesDetailsEditButton = By.CssSelector("button[title='Edit Sale']"); private By dispositionSalesDetailsMessage = By.XPath("//p[contains(text(),'There are no sale details indicated with this disposition file.')]"); + private By dispositionSalesDetailsCreateSubtitle = By.XPath("//div[contains(text(), 'Sales Details')]"); private By dispositionSalesDetailsPurchaserNameLabel = By.XPath("//label[contains(text(),'Purchaser name(s)')]"); private By dispositionSalesDetailsPurchaserNameLink = By.XPath("//button/div[contains(text(),'+ Add another purchaser')]"); - private By dispositionSalesDetailsPurchaserNameInput = By.XPath("input-dispositionPurchasers.0.contact.id"); + private By dispositionSalesDetailsPurchaserNameContent = By.CssSelector("div[data-testid='disposition-sale.purchasers']"); + private By dispositionSalesDetails1stPurchaserNameButton = By.CssSelector("div[data-testid='purchaserRow[0]'] button[@title='Select Contact']"); + private By dispositionSalesDetails1stPurchaserNameDeleteBttn = By.CssSelector("div[data-testid='purchaserRow[0]'] button[title='Remove Purchaser']"); + private By dispositionSalesDetailsPurchaserAgentLabel = By.XPath("//label[contains(text(),'Purchaser agent')]"); private By dispositionSalesDetailsPurchaserAgentButton = By.XPath("//label[contains(text(),'Purchaser agent')]/parent::div/following-sibling::div/div/div/div/button[@title='Select Contact']"); private By dispositionSalesDetailsPurchaserAgentInput = By.XPath("//div/input[@id='input-dispositionPurchaserAgent.contact.id']/parent::div/parent::div"); + private By dispositionSalesDetailsPurchaserAgentPrimaryContactSelect = By.Id("input-dispositionPurchaserAgent.primaryContactId"); + private By dispositionSalesDetailsPurchaserSolicitorLabel = By.XPath("//label[contains(text(),'Purchaser solicitor')]"); - private By dispositionSalesDetailsPurchaserSolicitorButton = By.XPath("//label[contains(text(),'Purchaser solicitor')]/parent::div/following-sibling::div/div/div/div/button[@title='Select Contact']"); private By dispositionSalesDetailsPurchaserSolicitorInput = By.XPath("//div/input[@id='input-dispositionPurchaserSolicitor.contact.id']/parent::div/parent::div"); + private By dispositionSalesDetailsPurchaserSolicitorButton = By.XPath("//label[contains(text(),'Purchaser solicitor')]/parent::div/following-sibling::div/div/div/div/button[@title='Select Contact']"); + private By dispositionSalesDetailsPurchaserSolicitorPrimaryContactSelect = By.Id("input-dispositionPurchaserSolicitor.primaryContactId"); + private By dispositionSalesDetailsRemovalDateLabel = By.XPath("//label[contains(text(),'Last condition removal date')]"); private By dispositionSalesDetailsRemovalDateContent = By.XPath("//label[contains(text(),'Last condition removal date')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsRemovalDateInput = By.Id("datepicker-finalConditionRemovalDate"); private By dispositionSalesDetailsRemovalDateTooltip = By.XPath("//label[contains(text(),'Last condition removal date')]/span/span[@data-testid='tooltip-icon-section-field-tooltip']"); + private By dispositionSalesDetailsCompletionDateLabel = By.XPath("//label[contains(text(),'Sale completion date')]"); private By dispositionSalesDetailsCompletionDateContent = By.XPath("//label[contains(text(),'Sale completion date')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsCompletionDateInput = By.Id("datepicker-saleCompletionDate"); + private By dispositionSalesDetailsFiscalYearLabel = By.XPath("//label[contains(text(),'Fiscal year of sale')]"); private By dispositionSalesDetailsFiscalYearContent = By.XPath("//label[contains(text(),'Fiscal year of sale')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsFiscalYearInput = By.Id("datepicker-saleFiscalYear"); + private By dispositionSalesDetailsSalePriceLabel = By.XPath("//label[contains(text(),'Final sale price ($)')]"); private By dispositionSalesDetailsSalePriceContent = By.XPath("//label[contains(text(),'Final sale price ($)')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsSalePriceInput = By.Id("input-finalSaleAmount"); + private By dispositionSalesDetailsRealtorCommissionLabel = By.XPath("//label[contains(text(),'Realtor commission ($)')]"); private By dispositionSalesDetailsRealtorCommissionContent = By.XPath("//label[contains(text(),'Realtor commission ($)')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsRealtorCommissionInput = By.Id("input-realtorCommissionAmount"); + private By dispositionSalesDetailsGSTLabel = By.XPath("//label[contains(text(),'GST required')]"); private By dispositionSalesDetailsGSTContent = By.XPath("//label[contains(text(),'GST required')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsGSTSelect = By.Id("input-isGstRequired"); + + private By dispositionSalesDetailsGSTCollectedLabel = By.XPath("//label[contains(text(),'GST collected ($)')]"); + private By dispositionSalesDetailsGSTCollectedContent = By.XPath("//label[contains(text(),'GST collected ($)')]/parent::div/following-sibling::div"); + private By dispositionSalesDetailsGSTCollectedInput = By.Id("input-gstCollectedAmount"); + private By dispositionSalesDetailsNetBookValueLabel = By.XPath("//label[contains(text(),'Net Book Value ($)')]"); private By dispositionSalesDetailsNetBookValueContent = By.XPath("//label[contains(text(),'Net Book Value ($)')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsNetBookValueInput = By.Id("input-netBookAmount"); + private By dispositionSalesDetailsTotalCostSaleLabel = By.XPath("//label[contains(text(),'Total cost of sales ($)')]"); private By dispositionSalesDetailsTotalCostSaleContent = By.XPath("//label[contains(text(),'Total cost of sales ($)')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsTotalCostSaleInput = By.Id("input-totalCostAmount"); private By dispositionSalesDetailsTotalCostSaleTooltip = By.XPath("//label[contains(text(),'Total cost of sales ($)')]/span/span[@data-testid='tooltip-icon-section-field-tooltip']"); + private By dispositionSalesDetailsBeforeSppLabel = By.XPath("//label[contains(text(),'Net proceeds before SPP cost ($)')]"); private By dispositionSalesDetailsBeforeSppContent = By.XPath("//label[contains(text(),'Net proceeds before SPP cost ($)')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsBeforeSppInput = By.Id("input-netProceedsBeforeSppAmount"); + private By dispositionSalesDetailsSppAmountLabel = By.XPath("//label[contains(text(),'SPP Amount ($)')]"); private By dispositionSalesDetailsSppAmountContent = By.XPath("//label[contains(text(),'SPP Amount ($)')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsSppAmountInput = By.Id("input-sppAmount"); private By dispositionSalesDetailsSppAmountTooltip = By.XPath("//label[contains(text(),'SPP Amount ($)')]/span/span[@data-testid='tooltip-icon-section-field-tooltip']"); + private By dispositionSalesDetailsAfterSppLabel = By.XPath("//label[contains(text(),'Net proceeds after SPP cost ($)')]"); private By dispositionSalesDetailsAfterSppContent = By.XPath("//label[contains(text(),'Net proceeds after SPP cost ($)')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsAfterSppInput = By.Id("input-netProceedsAfterSppAmount"); private By dispositionSalesDetailsAfterSppTooltip = By.XPath("//label[contains(text(),'Net proceeds after SPP cost ($)')]/span/span[@data-testid='tooltip-icon-section-field-tooltip']"); + private By dispositionSalesDetailsRemediationCostLabel = By.XPath("//label[contains(text(),'Remediation cost ($)')]"); private By dispositionSalesDetailsRemediationCostContent = By.XPath("//label[contains(text(),'Remediation cost ($)')]/parent::div/following-sibling::div"); private By dispositionSalesDetailsRemediationCostInput = By.Id("input-remediationAmount"); @@ -109,7 +134,6 @@ public class DispositionOfferSale : PageObjectBase private SharedSelectContact sharedSelectContact; private SharedModals sharedModals; - public DispositionOfferSale(IWebDriver webDriver) : base(webDriver) { sharedModals = new SharedModals(webDriver); @@ -173,27 +197,27 @@ public void CancelDispositionFileOffersAndSale() AssertTrueIsDisplayed(dispositionAppraisalEditButton); } - public void CreateNewAppraisalAndAssessment(DispositionFile appraisalandassessment) + public void CreateNewAppraisalAndAssessment(DispositionFile dispositionFile) { Wait(); - webDriver.FindElement(dispositionAppraisalValueInput).SendKeys(appraisalandassessment.AppraisalAndAssessmentValue); + webDriver.FindElement(dispositionAppraisalValueInput).SendKeys(dispositionFile.AppraisalAndAssessmentValue); - if (appraisalandassessment.AppraisalAndAssessmentDate != "") + if (dispositionFile.AppraisalAndAssessmentDate != "") { - webDriver.FindElement(dispositionAppraisalDateInput).SendKeys(appraisalandassessment.AppraisalAndAssessmentDate); + webDriver.FindElement(dispositionAppraisalDateInput).SendKeys(dispositionFile.AppraisalAndAssessmentDate); webDriver.FindElement(dispositionAppraisalDateInput).SendKeys(Keys.Enter); } - webDriver.FindElement(dispositionBcAssessmentValueInput).SendKeys(appraisalandassessment.AppraisalAndAssessmentBcAssessmentValue); + webDriver.FindElement(dispositionBcAssessmentValueInput).SendKeys(dispositionFile.AppraisalAndAssessmentBcAssessmentValue); - if (appraisalandassessment.AppraisalAndAssessmentBcAssessmentRollYear != "") + if (dispositionFile.AppraisalAndAssessmentBcAssessmentRollYear != "") { - webDriver.FindElement(dispositionBcAssessmentRollYearInput).SendKeys(appraisalandassessment.AppraisalAndAssessmentBcAssessmentRollYear); + webDriver.FindElement(dispositionBcAssessmentRollYearInput).SendKeys(dispositionFile.AppraisalAndAssessmentBcAssessmentRollYear); webDriver.FindElement(dispositionBcAssessmentRollYearInput).SendKeys(Keys.Enter); } - webDriver.FindElement(dispositionListPriceInput).SendKeys(appraisalandassessment.AppraisalAndAssessmentListPrice); + webDriver.FindElement(dispositionListPriceInput).SendKeys(dispositionFile.AppraisalAndAssessmentListPrice); } @@ -202,6 +226,8 @@ public void CreateNewOffer(DispositionOfferAndSale offer) Wait(); webDriver.FindElement(addOffersButton).Click(); + VerifyInitOfferForm(); + Wait(); if(offer.OfferOfferStatus != "") ChooseSpecificSelectOption(dispositionOfferStatusSelect, offer.OfferOfferStatus); @@ -234,96 +260,39 @@ public void CreateNewOffer(DispositionOfferAndSale offer) } } - public void CreateNewSalesDetails(DispositionFile salesdetails) + public void UpdateAppraisalAndAssessment(DispositionFile dispositionFile) { Wait(); - - if (salesdetails.PurchaserNames!.Count > 0) - { - for (var i = 0; i < salesdetails.PurchaserNames.Count; i++) - { - AddPurchaseMembers(salesdetails.PurchaserNames[i]); - } - } - - if (salesdetails.PurchaserAgent != "") - { - WaitUntilVisible(dispositionSalesDetailsPurchaserAgentButton); - webDriver.FindElement(dispositionSalesDetailsPurchaserAgentButton).Click(); - sharedSelectContact.SelectContact(salesdetails.PurchaserAgent, "persons"); - } - - if (salesdetails.PurchaserSolicitor != "") - { - WaitUntilVisible(dispositionSalesDetailsPurchaserSolicitorButton); - webDriver.FindElement(dispositionSalesDetailsPurchaserSolicitorButton).Click(); - sharedSelectContact.SelectContact(salesdetails.PurchaserSolicitor, "persons"); - } - - if (salesdetails.LastConditionRemovalDate != "") - { - webDriver.FindElement(dispositionSalesDetailsRemovalDateInput).SendKeys(salesdetails.LastConditionRemovalDate); - webDriver.FindElement(dispositionSalesDetailsRemovalDateInput).SendKeys(Keys.Enter); - } - if (salesdetails.SaleCompletionDate != "") - { - webDriver.FindElement(dispositionSalesDetailsCompletionDateInput).SendKeys(salesdetails.SaleCompletionDate); - webDriver.FindElement(dispositionSalesDetailsCompletionDateInput).SendKeys(Keys.Enter); - } - if (salesdetails.FiscalYearOfSale != "") - { - webDriver.FindElement(dispositionSalesDetailsFiscalYearInput).SendKeys(salesdetails.FiscalYearOfSale); - webDriver.FindElement(dispositionSalesDetailsFiscalYearInput).SendKeys(Keys.Enter); - } - - webDriver.FindElement(dispositionSalesDetailsSalePriceInput).SendKeys(salesdetails.FinalSalePrice); - - webDriver.FindElement(dispositionSalesDetailsRealtorCommissionInput).SendKeys(salesdetails.RealtorCommission); - - ChooseSpecificSelectOption(dispositionSalesDetailsGSTSelect, salesdetails.GSTRequired); - - webDriver.FindElement(dispositionSalesDetailsNetBookValueInput).SendKeys(salesdetails.NetBookValue); - - webDriver.FindElement(dispositionSalesDetailsTotalCostSaleInput).SendKeys(salesdetails.TotalCostOfSales); - - webDriver.FindElement(dispositionSalesDetailsSppAmountInput).SendKeys(salesdetails.SPPAmount); - - webDriver.FindElement(dispositionSalesDetailsRemediationCostInput).SendKeys(salesdetails.RemediationCost); - } - - public void UpdateAppraisalAndAssessment(DispositionFile appraisalandassessmentUpdate) - { - Wait(); - if (appraisalandassessmentUpdate.AppraisalAndAssessmentValue != "") + if (dispositionFile.AppraisalAndAssessmentValue != "") { ClearInput(dispositionAppraisalValueInput); - webDriver.FindElement(dispositionAppraisalValueInput).SendKeys(appraisalandassessmentUpdate.AppraisalAndAssessmentValue); + webDriver.FindElement(dispositionAppraisalValueInput).SendKeys(dispositionFile.AppraisalAndAssessmentValue); } - if (appraisalandassessmentUpdate.AppraisalAndAssessmentDate != "") + if (dispositionFile.AppraisalAndAssessmentDate != "") { ClearInput(dispositionAppraisalDateInput); - webDriver.FindElement(dispositionAppraisalDateInput).SendKeys(appraisalandassessmentUpdate.AppraisalAndAssessmentDate); + webDriver.FindElement(dispositionAppraisalDateInput).SendKeys(dispositionFile.AppraisalAndAssessmentDate); webDriver.FindElement(dispositionAppraisalDateInput).SendKeys(Keys.Enter); } - if (appraisalandassessmentUpdate.AppraisalAndAssessmentBcAssessmentValue != "") + if (dispositionFile.AppraisalAndAssessmentBcAssessmentValue != "") { ClearInput(dispositionBcAssessmentValueInput); - webDriver.FindElement(dispositionBcAssessmentValueInput).SendKeys(appraisalandassessmentUpdate.AppraisalAndAssessmentBcAssessmentValue); + webDriver.FindElement(dispositionBcAssessmentValueInput).SendKeys(dispositionFile.AppraisalAndAssessmentBcAssessmentValue); } - if (appraisalandassessmentUpdate.AppraisalAndAssessmentBcAssessmentRollYear != "") + if (dispositionFile.AppraisalAndAssessmentBcAssessmentRollYear != "") { ClearInput(dispositionBcAssessmentRollYearInput); - webDriver.FindElement(dispositionBcAssessmentRollYearInput).SendKeys(appraisalandassessmentUpdate.AppraisalAndAssessmentBcAssessmentRollYear); + webDriver.FindElement(dispositionBcAssessmentRollYearInput).SendKeys(dispositionFile.AppraisalAndAssessmentBcAssessmentRollYear); webDriver.FindElement(dispositionBcAssessmentRollYearInput).SendKeys(Keys.Enter); } - if (appraisalandassessmentUpdate.AppraisalAndAssessmentListPrice != "") + if (dispositionFile.AppraisalAndAssessmentListPrice != "") { ClearInput(dispositionListPriceInput); - webDriver.FindElement(dispositionListPriceInput).SendKeys(appraisalandassessmentUpdate.AppraisalAndAssessmentListPrice); + webDriver.FindElement(dispositionListPriceInput).SendKeys(dispositionFile.AppraisalAndAssessmentListPrice); } } @@ -368,6 +337,120 @@ public void UpdateOffers(DispositionOfferAndSale offerUpdate, int index) { } } + public void InsertSalesDetails(DispositionFile dispositionFile) + { + Wait(); + while (webDriver.FindElements(dispositionSalesDetails1stPurchaserNameDeleteBttn).Count > 0) + { + webDriver.FindElement(dispositionSalesDetails1stPurchaserNameDeleteBttn).Click(); + + Wait(); + Assert.Equal("Remove Purchaser", sharedModals.ModalHeader()); + Assert.Equal("Do you wish to remove this purchaser?", sharedModals.ModalContent()); + + sharedModals.ModalClickOKBttn(); + } + + if (dispositionFile.PurchaserNames!.Count > 0) + { + for (var i = 0; i < dispositionFile.PurchaserNames.Count; i++) + AddPurchaseNames(dispositionFile.PurchaserNames[i], i); + } + + if (dispositionFile.PurchaserAgent != "") + { + WaitUntilVisible(dispositionSalesDetailsPurchaserAgentButton); + webDriver.FindElement(dispositionSalesDetailsPurchaserAgentButton).Click(); + sharedSelectContact.SelectContact(dispositionFile.PurchaserAgent, dispositionFile.PurchaserAgentType); + } + + Wait(); + if (webDriver.FindElements(dispositionSalesDetailsPurchaserAgentPrimaryContactSelect).Count > 0) + ChooseSpecificSelectOption(dispositionSalesDetailsPurchaserAgentPrimaryContactSelect, dispositionFile.PurchaserAgentPrimaryContact); + + if (dispositionFile.PurchaserSolicitor != "") + { + WaitUntilVisible(dispositionSalesDetailsPurchaserSolicitorButton); + webDriver.FindElement(dispositionSalesDetailsPurchaserSolicitorButton).Click(); + sharedSelectContact.SelectContact(dispositionFile.PurchaserSolicitor, dispositionFile.PurchaserSolicitorType); + } + + Wait(); + if (webDriver.FindElements(dispositionSalesDetailsPurchaserSolicitorPrimaryContactSelect).Count > 0) + ChooseSpecificSelectOption(dispositionSalesDetailsPurchaserSolicitorPrimaryContactSelect, dispositionFile.PurchaserSolicitorPrimaryContact); + + if (dispositionFile.LastConditionRemovalDate != "") + { + ClearInput(dispositionSalesDetailsRemovalDateInput); + webDriver.FindElement(dispositionSalesDetailsRemovalDateInput).SendKeys(dispositionFile.LastConditionRemovalDate); + webDriver.FindElement(dispositionSalesDetailsRemovalDateInput).SendKeys(Keys.Enter); + } + if (dispositionFile.SaleCompletionDate != "") + { + ClearInput(dispositionSalesDetailsCompletionDateInput); + webDriver.FindElement(dispositionSalesDetailsCompletionDateInput).SendKeys(dispositionFile.SaleCompletionDate); + webDriver.FindElement(dispositionSalesDetailsCompletionDateInput).SendKeys(Keys.Enter); + } + if (dispositionFile.FiscalYearOfSale != "") + { + ClearInput(dispositionSalesDetailsFiscalYearInput); + webDriver.FindElement(dispositionSalesDetailsFiscalYearInput).SendKeys(dispositionFile.FiscalYearOfSale); + webDriver.FindElement(dispositionSalesDetailsFiscalYearInput).SendKeys(Keys.Enter); + } + + if (dispositionFile.FinalSalePrice != "") + { + ClearInput(dispositionSalesDetailsSalePriceInput); + webDriver.FindElement(dispositionSalesDetailsSalePriceInput).SendKeys(dispositionFile.FinalSalePrice); + } + + if (dispositionFile.RealtorCommission != "") + { + ClearInput(dispositionSalesDetailsRealtorCommissionInput); + webDriver.FindElement(dispositionSalesDetailsRealtorCommissionInput).SendKeys(dispositionFile.RealtorCommission); + } + + ChooseSpecificSelectOption(dispositionSalesDetailsGSTSelect, dispositionFile.GSTRequired); + + Wait(); + if (webDriver.FindElements(dispositionFileConfirmationModal).Count > 0) + { + Assert.Equal("Confirm Change", sharedModals.ModalHeader()); + Assert.Equal("The GST, if provided, will be cleared. Do you wish to proceed?", sharedModals.ModalContent()); + sharedModals.ModalClickOKBttn(); + } + + if (dispositionFile.GSTRequired.Equals("Yes")) + { + AssertTrueIsDisplayed(dispositionSalesDetailsGSTCollectedLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsGSTCollectedInput); + } + + if (dispositionFile.NetBookValue != "") + { + ClearInput(dispositionSalesDetailsNetBookValueInput); + webDriver.FindElement(dispositionSalesDetailsNetBookValueInput).SendKeys(dispositionFile.NetBookValue); + } + + if (dispositionFile.TotalCostOfSales != "") + { + ClearInput(dispositionSalesDetailsTotalCostSaleInput); + webDriver.FindElement(dispositionSalesDetailsTotalCostSaleInput).SendKeys(dispositionFile.TotalCostOfSales); + } + + if (dispositionFile.SPPAmount != "") + { + ClearInput(dispositionSalesDetailsSppAmountInput); + webDriver.FindElement(dispositionSalesDetailsSppAmountInput).SendKeys(dispositionFile.SPPAmount); + } + + if (dispositionFile.RemediationCost != "") + { + ClearInput(dispositionSalesDetailsRemediationCostInput); + webDriver.FindElement(dispositionSalesDetailsRemediationCostInput).SendKeys(dispositionFile.RemediationCost); + } + } + public void VerifyInitOffersAndSaleTab() { AssertTrueIsDisplayed(offersAndSaleAppraisalAndAssessmentSubtitle); @@ -378,6 +461,82 @@ public void VerifyInitOffersAndSaleTab() AssertTrueIsDisplayed(dispositionSalesDetailsMessage); } + public void VerifyInitAppraisalAndAssessmentForm() + { + AssertTrueIsDisplayed(dispositionAppraisalAndAssessmentCreateFormSubtitle); + + AssertTrueIsDisplayed(dispositionAppraisalValueLabel); + AssertTrueIsDisplayed(dispositionAppraisalValueInput); + + AssertTrueIsDisplayed(dispositionAppraisalDateLabel); + AssertTrueIsDisplayed(dispositionAppraisalDateInput); + + AssertTrueIsDisplayed(dispositionBcAssessmentValueLabel); + AssertTrueIsDisplayed(dispositionBcAssessmentValueInput); + + AssertTrueIsDisplayed(dispositionBcAssessmentRollYearLabel); + AssertTrueIsDisplayed(dispositionBcAssessmentRollYearInput); + + AssertTrueIsDisplayed(dispositionListPriceLabel); + AssertTrueIsDisplayed(dispositionListPriceInput); + } + + public void VerifyInitSalesDetailsForm() + { + AssertTrueIsDisplayed(dispositionSalesDetailsCreateSubtitle); + + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserNameLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserNameLink); + + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserAgentLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserAgentInput); + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserAgentButton); + + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserSolicitorLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserSolicitorInput); + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserSolicitorButton); + + AssertTrueIsDisplayed(dispositionSalesDetailsRemovalDateLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsRemovalDateTooltip); + AssertTrueIsDisplayed(dispositionSalesDetailsRemovalDateInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsCompletionDateLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsCompletionDateInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsFiscalYearLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsFiscalYearInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsSalePriceLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsSalePriceInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsRealtorCommissionLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsRealtorCommissionInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsGSTLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsGSTSelect); + + AssertTrueIsDisplayed(dispositionSalesDetailsNetBookValueLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsNetBookValueInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsTotalCostSaleLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsTotalCostSaleTooltip); + AssertTrueIsDisplayed(dispositionSalesDetailsTotalCostSaleInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsBeforeSppLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsBeforeSppInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsSppAmountLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsSppAmountTooltip); + AssertTrueIsDisplayed(dispositionSalesDetailsSppAmountInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsAfterSppLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsAfterSppTooltip); + AssertTrueIsDisplayed(dispositionSalesDetailsAfterSppInput); + + AssertTrueIsDisplayed(dispositionSalesDetailsRemediationCostLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsRemediationCostInput); + } + public void VerifyCreatedAppraisalAndAssessment(DispositionFile disposition) { AssertTrueIsDisplayed(offersAndSaleAppraisalAndAssessmentSubtitle); @@ -387,6 +546,7 @@ public void VerifyCreatedAppraisalAndAssessment(DispositionFile disposition) AssertTrueContentEquals(dispositionAppraisalValueContent, TransformCurrencyFormat(disposition.AppraisalAndAssessmentValue)); AssertTrueIsDisplayed(dispositionAppraisalDateLabel); + System.Diagnostics.Debug.WriteLine(dispositionAppraisalDateContent); if(disposition.AppraisalAndAssessmentDate != "") AssertTrueContentEquals(dispositionAppraisalDateContent, TransformDateFormat(disposition.AppraisalAndAssessmentDate)); @@ -436,7 +596,26 @@ public void VerifyCreatedSalesDetails(DispositionFile disposition) { AssertTrueIsDisplayed(offersAndSaleSalesDetailsSubtitle); - AssertTrueIsDisplayed(dispositionSalesDetailsRemovalDateLabel); + AssertTrueIsDisplayed(dispositionSalesDetailsPurchaserNameLabel); + if (disposition.PurchaserNames!.Count > 0) + { + var memberLinkCount = 0; + var purchaserNames = webDriver.FindElement(dispositionSalesDetailsPurchaserNameContent).FindElements(By.TagName("a")); + + for (int i = 0; i < disposition.PurchaserNames.Count; i++) + { + Assert.Equal(disposition.PurchaserNames[i].PurchaserName, purchaserNames[memberLinkCount].Text); + if (disposition.PurchaserNames[i].PurchaseMemberPrimaryContact != "") + { + memberLinkCount++; + Assert.Equal(disposition.PurchaserNames[i].PurchaseMemberPrimaryContact, purchaserNames[memberLinkCount].Text); + } + + memberLinkCount++; + } + } + + AssertTrueIsDisplayed(dispositionSalesDetailsRemovalDateLabel); if (disposition.LastConditionRemovalDate != "") AssertTrueContentEquals(dispositionSalesDetailsRemovalDateContent, TransformDateFormat(disposition.LastConditionRemovalDate)); @@ -444,6 +623,10 @@ public void VerifyCreatedSalesDetails(DispositionFile disposition) if (disposition.SaleCompletionDate != "") AssertTrueContentEquals(dispositionSalesDetailsCompletionDateContent, TransformDateFormat(disposition.SaleCompletionDate)); + AssertTrueIsDisplayed(dispositionSalesDetailsFiscalYearLabel); + if(disposition.FiscalYearOfSale != "") + AssertTrueContentEquals(dispositionSalesDetailsFiscalYearContent, disposition.FiscalYearOfSale); + AssertTrueIsDisplayed(dispositionSalesDetailsSalePriceLabel); if (disposition.FinalSalePrice != "") AssertTrueContentEquals(dispositionSalesDetailsSalePriceContent, TransformCurrencyFormat(disposition.FinalSalePrice)); @@ -452,33 +635,72 @@ public void VerifyCreatedSalesDetails(DispositionFile disposition) if (disposition.RealtorCommission != "") AssertTrueContentEquals(dispositionSalesDetailsRealtorCommissionContent, TransformCurrencyFormat(disposition.RealtorCommission)); + AssertTrueIsDisplayed(dispositionSalesDetailsGSTLabel); + AssertTrueContentEquals(dispositionSalesDetailsGSTContent, disposition.GSTRequired); + AssertTrueIsDisplayed(dispositionSalesDetailsNetBookValueLabel); if (disposition.NetBookValue != "") AssertTrueContentEquals(dispositionSalesDetailsNetBookValueContent, TransformCurrencyFormat(disposition.NetBookValue)); - AssertTrueIsDisplayed(dispositionSalesDetailsFiscalYearLabel); - AssertTrueContentEquals(dispositionSalesDetailsFiscalYearContent, disposition.FiscalYearOfSale); - AssertTrueIsDisplayed(dispositionSalesDetailsTotalCostSaleLabel); if (disposition.TotalCostOfSales != "") AssertTrueContentEquals(dispositionSalesDetailsTotalCostSaleContent, TransformCurrencyFormat(disposition.TotalCostOfSales)); + AssertTrueIsDisplayed(dispositionSalesDetailsBeforeSppLabel); + if(disposition.NetProceedsBeforeSPP != "") + AssertTrueContentEquals(dispositionSalesDetailsBeforeSppContent, TransformCurrencyFormat(disposition.NetProceedsBeforeSPP)); + AssertTrueIsDisplayed(dispositionSalesDetailsSppAmountLabel); if (disposition.SPPAmount != "") AssertTrueContentEquals(dispositionSalesDetailsSppAmountContent, TransformCurrencyFormat(disposition.SPPAmount)); + AssertTrueIsDisplayed(dispositionSalesDetailsAfterSppLabel); + if (disposition.NetProceedsAfterSPP != "") + AssertTrueContentEquals(dispositionSalesDetailsAfterSppContent, TransformCurrencyFormat(disposition.NetProceedsAfterSPP)); + AssertTrueIsDisplayed(dispositionSalesDetailsRemediationCostLabel); if (disposition.RemediationCost != "") AssertTrueContentEquals(dispositionSalesDetailsRemediationCostContent, TransformCurrencyFormat(disposition.RemediationCost)); } + private void VerifyInitOfferForm() + { + AssertTrueIsDisplayed(dispositionOfferCreateSubtitle); + + AssertTrueIsDisplayed(dispositionOfferStatusLabel); + AssertTrueIsDisplayed(dispositionOfferStatusTooltip); + AssertTrueIsDisplayed(dispositionOfferStatusSelect); - private void AddPurchaseMembers(PurchaseMember purchaseMember) + AssertTrueIsDisplayed(dispositionOfferNameLabel); + AssertTrueIsDisplayed(dispositionOfferNameInput); + + AssertTrueIsDisplayed(dispositionOfferDateLabel); + AssertTrueIsDisplayed(dispositionOfferDateInput); + + AssertTrueIsDisplayed(dispositionOfferExpiryDateLabel); + AssertTrueIsDisplayed(dispositionOfferExpiryDateInput); + + AssertTrueIsDisplayed(dispositionOfferPriceLabel); + AssertTrueIsDisplayed(dispositionOfferPriceInput); + + AssertTrueIsDisplayed(dispositionOfferNotesLabel); + AssertTrueIsDisplayed(dispositionOfferNotesInput); + AssertTrueIsDisplayed(dispositionOfferNotesTooltip); + } + + private void AddPurchaseNames(PurchaseMember purchaseMember, int index) { Wait(); FocusAndClick(dispositionSalesDetailsPurchaserNameLink); - FocusAndClick(By.CssSelector("div[data-testid='purchaserRow[+ Index + ]'] button[title='Select Contact']")); + + FocusAndClick(By.CssSelector("div[data-testid='purchaserRow["+ index +"]'] button[title='Select Contact']")); sharedSelectContact.SelectContact(purchaseMember.PurchaserName, purchaseMember.PurchaseMemberContactType); + + Wait(); + if (webDriver.FindElements(By.Id("input-dispositionPurchasers."+ index +".primaryContactId")).Count > 0) + { + webDriver.FindElement(By.Id("input-dispositionPurchasers."+ index +".primaryContactId")).SendKeys(purchaseMember.PurchaseMemberPrimaryContact); + } } } } diff --git a/testing/PIMS.Tests.Automation/PageObjects/PageObjectBase.cs b/testing/PIMS.Tests.Automation/PageObjects/PageObjectBase.cs index c7e65883ec..45e081adb2 100644 --- a/testing/PIMS.Tests.Automation/PageObjects/PageObjectBase.cs +++ b/testing/PIMS.Tests.Automation/PageObjects/PageObjectBase.cs @@ -18,7 +18,6 @@ protected PageObjectBase(IWebDriver webDriver) { this.webDriver = webDriver; wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(120)); - //wait.IgnoreExceptionTypes(typeof(NoSuchElementException), typeof(StaleElementReferenceException), typeof(ElementClickInterceptedException)); } protected virtual void Wait(int milliseconds = 3000) => Thread.Sleep(milliseconds); @@ -35,31 +34,15 @@ protected void WaitUntilTableSpinnerDisappear() Wait(); } - protected void WaitUntilStale(By element) - { - wait.Until(ExpectedConditions.StalenessOf(webDriver.FindElement(element))); - } + protected void WaitUntilStale(By element) => wait.Until(ExpectedConditions.StalenessOf(webDriver.FindElement(element))); - protected void WaitUntilDisappear(By element) - { - wait.Until(ExpectedConditions.InvisibilityOfElementLocated(element)); - //Wait(); - } + protected void WaitUntilDisappear(By element) => wait.Until(ExpectedConditions.InvisibilityOfElementLocated(element)); - protected void WaitUntilVisible(By element) - { - wait.Until(ExpectedConditions.ElementIsVisible(element)); - } + protected void WaitUntilVisible(By element) => wait.Until(ExpectedConditions.ElementIsVisible(element)); - protected void WaitUntilExist(By element) - { - wait.Until(ExpectedConditions.ElementExists(element)); - } + protected void WaitUntilExist(By element) => wait.Until(ExpectedConditions.ElementExists(element)); - protected void WaitUntilClickable(By element) - { - wait.Until(ExpectedConditions.ElementToBeClickable(element)); - } + protected void WaitUntilClickable(By element) => wait.Until(ExpectedConditions.ElementToBeClickable(element)); public void WaitUntilVisibleText(By element, string text) { diff --git a/testing/PIMS.Tests.Automation/StepDefinitions/DispositionFileSteps.cs b/testing/PIMS.Tests.Automation/StepDefinitions/DispositionFileSteps.cs index 7c7c1781d7..1685b22441 100644 --- a/testing/PIMS.Tests.Automation/StepDefinitions/DispositionFileSteps.cs +++ b/testing/PIMS.Tests.Automation/StepDefinitions/DispositionFileSteps.cs @@ -251,14 +251,15 @@ public void CreateOfferAndSalesAppraisalAndAssessment() offerSale.VerifyInitOffersAndSaleTab(); // Create AppraisalAndAssessment section by clicking edit button - // offerSale.EditAppraisalAndAssessmentButton(); - //offerSale.CreateNewAppraisalAndAssessment(dispositionFile); + offerSale.EditAppraisalAndAssessmentButton(); + offerSale.VerifyInitAppraisalAndAssessmentForm(); + offerSale.CreateNewAppraisalAndAssessment(dispositionFile); //Save the AppraisalAndAssessment section from - //offerSale.SaveDispositionFileOffersAndSale(); + offerSale.SaveDispositionFileOffersAndSale(); //Verify Created Appraisal and Assessment form - //offerSale.VerifyCreatedAppraisalAndAssessment(dispositionFile); + offerSale.VerifyCreatedAppraisalAndAssessment(dispositionFile); //Add and verify Offers if (dispositionFile.DispositionOfferAndSale.Count > 0) @@ -274,7 +275,8 @@ public void CreateOfferAndSalesAppraisalAndAssessment() // Create Sales Details section by clicking edit button offerSale.EditSalesDetailsButton(); - offerSale.CreateNewSalesDetails(dispositionFile); + offerSale.VerifyInitSalesDetailsForm(); + offerSale.InsertSalesDetails(dispositionFile); //Save the Sales Details section from offerSale.SaveDispositionFileOffersAndSale(); @@ -335,6 +337,19 @@ public void UpdateOfferAndSalesAppraisalAndAssessment(int rowNumber) //Delete Offer offerSale.DeleteOffer(0); + + //Update Sales Details and cancel changes + offerSale.EditSalesDetailsButton(); + offerSale.InsertSalesDetails(dispositionFile); + offerSale.CancelDispositionFileOffersAndSale(); + + //Update Sales Details and save changes + offerSale.EditSalesDetailsButton(); + offerSale.InsertSalesDetails(dispositionFile); + offerSale.SaveDispositionFileOffersAndSale(); + + //Verify Sales Details + offerSale.VerifyCreatedSalesDetails(dispositionFile); } [StepDefinition(@"I create a Disposition File from a pin on map from row number (.*)")] @@ -451,7 +466,7 @@ private void PopulateDispositionFile(int rowNumber) dispositionFile.DispositionProjFunding = ExcelDataContext.ReadData(rowNumber, "DispositionProjFunding"); //Schedule - dispositionFile.DispositionAssignedDate = ExcelDataContext.ReadData(rowNumber, "AssignedDate"); + dispositionFile.DispositionAssignedDate = ExcelDataContext.ReadData(rowNumber, "DispositionAssignedDate"); dispositionFile.DispositionCompletedDate = ExcelDataContext.ReadData(rowNumber, "DispositionCompletedDate"); //Disposition DetailsDisposition @@ -463,7 +478,7 @@ private void PopulateDispositionFile(int rowNumber) dispositionFile.InitiatingDocument = ExcelDataContext.ReadData(rowNumber, "InitiatingDocument"); dispositionFile.OtherInitiatingDocument = ExcelDataContext.ReadData(rowNumber, "OtherInitiatingDocument"); dispositionFile.InitiatingDocumentDate = ExcelDataContext.ReadData(rowNumber, "InitiatingDocumentDate"); - dispositionFile.PhysicalFileStatus = ExcelDataContext.ReadData(rowNumber, "PhysicalFileStatus"); + dispositionFile.DispositionPhysicalFileStatus = ExcelDataContext.ReadData(rowNumber, "DispositionPhysicalFileStatus"); dispositionFile.InitiatingBranch = ExcelDataContext.ReadData(rowNumber, "InitiatingBranch"); dispositionFile.DispositionMOTIRegion = ExcelDataContext.ReadData(rowNumber, "DispositionMOTIRegion"); @@ -475,7 +490,7 @@ private void PopulateDispositionFile(int rowNumber) PopulateTeamsCollection(dispositionFile.DispositionTeamStartRow, dispositionFile.DispositionTeamCount); //Properties Search - dispositionFile.DispositionSearchPropertiesIndex = int.Parse(ExcelDataContext.ReadData(rowNumber, "DisSearchPropertiesIndex")); + dispositionFile.DispositionSearchPropertiesIndex = int.Parse(ExcelDataContext.ReadData(rowNumber, "DispositionSearchPropertiesIndex")); if (dispositionFile.DispositionSearchPropertiesIndex > 0) { DataTable searchPropertiesSheet = ExcelDataContext.GetInstance().Sheets["SearchProperties"]!; @@ -537,34 +552,43 @@ private void PopulateDispositionFile(int rowNumber) dispositionFile.DispositionFileChecklist.SaleInformationSelect11 = ExcelDataContext.ReadData(dispositionFile.DispositionFileChecklistIndex, "SaleInformationSelect11"); } - // Disposition Offer and sales - dispositionFile.AppraisalAndAssessmentValue = ExcelDataContext.ReadData(rowNumber, "AppraisalAndAssessmentAppraisalValue"); - dispositionFile.AppraisalAndAssessmentDate = ExcelDataContext.ReadData(rowNumber, "AppraisalAndAssessmentAppraisalDate"); + // Disposition Offer and Sales - Appraisal & Assessment + dispositionFile.AppraisalAndAssessmentValue = ExcelDataContext.ReadData(rowNumber, "AppraisalAndAssessmentValue"); + dispositionFile.AppraisalAndAssessmentDate = ExcelDataContext.ReadData(rowNumber, "AppraisalAndAssessmentDate"); dispositionFile.AppraisalAndAssessmentBcAssessmentValue = ExcelDataContext.ReadData(rowNumber, "AppraisalAndAssessmentBcAssessmentValue"); dispositionFile.AppraisalAndAssessmentBcAssessmentRollYear = ExcelDataContext.ReadData(rowNumber, "AppraisalAndAssessmentBcAssessmentRollYear"); dispositionFile.AppraisalAndAssessmentListPrice = ExcelDataContext.ReadData(rowNumber, "AppraisalAndAssessmentListPrice"); + // Disposition Offer and Sales - Offers dispositionFile.OfferSaleStartRow = int.Parse(ExcelDataContext.ReadData(rowNumber, "OfferSaleStartRow")); dispositionFile.OfferSaleTotalCount = int.Parse(ExcelDataContext.ReadData(rowNumber, "OfferSaleTotalCount")); if (dispositionFile.OfferSaleStartRow > 0 && dispositionFile.OfferSaleTotalCount > 0) PopulateOfferSaleCollection(dispositionFile.OfferSaleStartRow, dispositionFile.OfferSaleTotalCount); + // Disposition Offer and Sales - Sales Details dispositionFile.PurchaseNameStartRow = int.Parse(ExcelDataContext.ReadData(rowNumber, "PurchaseNameStartRow")); dispositionFile.PurchaseNameTotalCount = int.Parse(ExcelDataContext.ReadData(rowNumber, "PurchaseNameTotalCount")); if (dispositionFile.PurchaseNameStartRow > 0 && dispositionFile.PurchaseNameTotalCount > 0) PopulatePurchaseNamesCollection(dispositionFile.PurchaseNameStartRow, dispositionFile.PurchaseNameTotalCount); dispositionFile.PurchaserAgent = ExcelDataContext.ReadData(rowNumber, "PurchaserAgent"); + dispositionFile.PurchaserAgentType = ExcelDataContext.ReadData(rowNumber, "PurchaserAgentType"); + dispositionFile.PurchaserAgentPrimaryContact = ExcelDataContext.ReadData(rowNumber, "PurchaserAgentPrimaryContact"); dispositionFile.PurchaserSolicitor = ExcelDataContext.ReadData(rowNumber, "PurchaserSolicitor"); + dispositionFile.PurchaserSolicitorType = ExcelDataContext.ReadData(rowNumber, "PurchaserSolicitorType"); + dispositionFile.PurchaserSolicitorPrimaryContact = ExcelDataContext.ReadData(rowNumber, "PurchaserSolicitorPrimaryContact"); dispositionFile.LastConditionRemovalDate = ExcelDataContext.ReadData(rowNumber, "LastConditionRemovalDate"); dispositionFile.SaleCompletionDate = ExcelDataContext.ReadData(rowNumber, "SaleCompletionDate"); dispositionFile.FiscalYearOfSale = ExcelDataContext.ReadData(rowNumber, "FiscalYearOfSale"); dispositionFile.FinalSalePrice = ExcelDataContext.ReadData(rowNumber, "FinalSalePrice"); dispositionFile.RealtorCommission = ExcelDataContext.ReadData(rowNumber, "RealtorCommission"); dispositionFile.GSTRequired = ExcelDataContext.ReadData(rowNumber, "GSTRequired"); + dispositionFile.GSTCollected = ExcelDataContext.ReadData(rowNumber, "GSTCollected"); dispositionFile.NetBookValue = ExcelDataContext.ReadData(rowNumber, "NetBookValue"); dispositionFile.TotalCostOfSales = ExcelDataContext.ReadData(rowNumber, "TotalCostOfSales"); + dispositionFile.NetProceedsBeforeSPP = ExcelDataContext.ReadData(rowNumber, "NetProceedsBeforeSPP"); dispositionFile.SPPAmount = ExcelDataContext.ReadData(rowNumber, "SPPAmount"); + dispositionFile.NetProceedsAfterSPP = ExcelDataContext.ReadData(rowNumber, "NetProceedsAfterSPP"); dispositionFile.RemediationCost = ExcelDataContext.ReadData(rowNumber, "RemediationCost"); } @@ -604,6 +628,7 @@ private void PopulateOfferSaleCollection(int startRow, int rowsCount) dispositionFile.DispositionOfferAndSale.Add(offerAndSale); } } + private void PopulatePurchaseNamesCollection(int startRow, int rowsCount) { DataTable purchaseSheet = ExcelDataContext.GetInstance().Sheets["PurchaserNames"]!;