From 49cff8211699d7afc81ac9eb4b4d38c1ef08b037 Mon Sep 17 00:00:00 2001 From: Jonas Metzener Date: Tue, 30 Aug 2022 12:53:10 +0200 Subject: [PATCH] feat(distribution): add functionality to reopen an inquiry --- .../distribution/addon/abilities/inquiry.js | 10 ++++++ .../addon/components/cd-inquiry-dialog.js | 30 ++++++++++++++++ .../cd-inquiry-dialog/inquiry-part.hbs | 7 ++++ .../cd-inquiry-dialog/inquiry-part.js | 30 ++++++++++++++++ .../components/cd-navigation/controls.js | 4 +-- .../addon/gql/fragments/inquiry.graphql | 1 + .../complete-inquiry-work-item.graphql | 1 + ...em.graphql => reopen-distribution.graphql} | 2 +- .../gql/mutations/reopen-inquiry.graphql | 33 ++++++++++++++++++ .../components/cd-inquiry-dialog-test.js | 34 +++++++++++++++++++ .../components/cd-navigation/controls-test.js | 2 +- packages/distribution/translations/de.yaml | 5 +++ packages/distribution/translations/en.yaml | 5 +++ packages/distribution/translations/fr.yaml | 5 +++ .../addon/mirage-graphql/mocks/work-item.js | 11 ++++-- .../testing/addon/scenarios/distribution.js | 2 +- 16 files changed, 174 insertions(+), 8 deletions(-) rename packages/distribution/addon/gql/mutations/{redo-work-item.graphql => reopen-distribution.graphql} (67%) create mode 100644 packages/distribution/addon/gql/mutations/reopen-inquiry.graphql diff --git a/packages/distribution/addon/abilities/inquiry.js b/packages/distribution/addon/abilities/inquiry.js index 445b97c52..e2e130800 100644 --- a/packages/distribution/addon/abilities/inquiry.js +++ b/packages/distribution/addon/abilities/inquiry.js @@ -56,4 +56,14 @@ export default class InquiryAbility extends Ability { ) ?? true ); } + + get canReopen() { + return ( + this.model.isRedoable && + this.model?.addressedGroups + .map(String) + .includes(String(this.calumaOptions.currentGroupId)) && + (this.config.permissions.reopenInquiry?.(this.model) ?? true) + ); + } } diff --git a/packages/distribution/addon/components/cd-inquiry-dialog.js b/packages/distribution/addon/components/cd-inquiry-dialog.js index 1bfd36110..35ecd28e5 100644 --- a/packages/distribution/addon/components/cd-inquiry-dialog.js +++ b/packages/distribution/addon/components/cd-inquiry-dialog.js @@ -52,6 +52,8 @@ export default class CdInquiryDialogComponent extends Component { }, }); + this._setRedoableStates(response.allWorkItems); + /** * Sadly this is necessary to handle what happens after the withdraw task in * the inquiry part component because the mutation triggers a refresh of the @@ -68,11 +70,39 @@ export default class CdInquiryDialogComponent extends Component { if (allWorkItems.edges.every((edge) => edge.node.status === "CANCELED")) { this.router.transitionTo("index"); } + + /** + * Get work item that was redoable in the previous calulation and is now + * not anymore. This indicates that the work item was redone which should + * result in a transition to the answer view. + */ + const redoneWorkItem = this._redoableStates.find((stateObj) => { + const updatedWorkItem = allWorkItems.edges.find( + (edge) => decodeId(edge.node.id) === stateObj.id + ); + + return ( + stateObj.isRedoable && !(updatedWorkItem?.node.isRedoable ?? true) + ); + }); + + if (redoneWorkItem) { + this.router.transitionTo("inquiry.detail.answer", redoneWorkItem.id); + } + + this._setRedoableStates(allWorkItems); }); return response; } + _setRedoableStates(allWorkItems) { + this._redoableStates = allWorkItems.edges.map((edge) => ({ + id: decodeId(edge.node.id), + isRedoable: edge.node.isRedoable, + })); + } + @dropTask *createInquiry(e) { e.preventDefault(); diff --git a/packages/distribution/addon/components/cd-inquiry-dialog/inquiry-part.hbs b/packages/distribution/addon/components/cd-inquiry-dialog/inquiry-part.hbs index d5b3cc748..71d042a4b 100644 --- a/packages/distribution/addon/components/cd-inquiry-dialog/inquiry-part.hbs +++ b/packages/distribution/addon/components/cd-inquiry-dialog/inquiry-part.hbs @@ -77,6 +77,13 @@ {{/if}} + {{#if (and (eq @type "answer") (can "reopen inquiry" @inquiry))}} +
  • + + {{t "caluma.distribution.reopen-inquiry.link"}} + +
  • + {{/if}} {{/unless}} diff --git a/packages/distribution/addon/components/cd-inquiry-dialog/inquiry-part.js b/packages/distribution/addon/components/cd-inquiry-dialog/inquiry-part.js index 2ec89b227..7cd00feda 100644 --- a/packages/distribution/addon/components/cd-inquiry-dialog/inquiry-part.js +++ b/packages/distribution/addon/components/cd-inquiry-dialog/inquiry-part.js @@ -7,6 +7,7 @@ import { confirm } from "ember-uikit"; import { decodeId } from "@projectcaluma/ember-core/helpers/decode-id"; import config from "@projectcaluma/ember-distribution/config"; +import reopenInquiryMutation from "@projectcaluma/ember-distribution/gql/mutations/reopen-inquiry.graphql"; import withdrawInquiryMutation from "@projectcaluma/ember-distribution/gql/mutations/withdraw-inquiry.graphql"; import inquiryAnswerStatus from "@projectcaluma/ember-distribution/utils/inquiry-answer-status"; @@ -73,4 +74,33 @@ export default class CdInquiryDialogInquiryPartComponent extends Component { ); } } + + @dropTask + *reopen(e) { + e.preventDefault(); + + /* istanbul ignore next */ + if ( + !(yield confirm( + this.intl.t("caluma.distribution.reopen-inquiry.confirm") + )) + ) { + return; + } + + try { + yield this.apollo.mutate({ + mutation: reopenInquiryMutation, + variables: { + workItem: decodeId(this.args.inquiry.id), + statusQuestion: this.config.inquiry.answer.statusQuestion, + buttonTasks: Object.keys(this.config.inquiry.answer.buttons), + }, + }); + } catch (error) { + this.notification.danger( + this.intl.t("caluma.distribution.reopen-inquiry.error") + ); + } + } } diff --git a/packages/distribution/addon/components/cd-navigation/controls.js b/packages/distribution/addon/components/cd-navigation/controls.js index 44f69194d..b69cf143e 100644 --- a/packages/distribution/addon/components/cd-navigation/controls.js +++ b/packages/distribution/addon/components/cd-navigation/controls.js @@ -8,7 +8,7 @@ import { gql } from "graphql-tag"; import { decodeId } from "@projectcaluma/ember-core/helpers/decode-id"; import config from "@projectcaluma/ember-distribution/config"; import completeWorkItemMutation from "@projectcaluma/ember-distribution/gql/mutations/complete-work-item.graphql"; -import redoWorkItemMutation from "@projectcaluma/ember-distribution/gql/mutations/redo-work-item.graphql"; +import reopenDistributionMutation from "@projectcaluma/ember-distribution/gql/mutations/reopen-distribution.graphql"; import incompleteInquiriesQuery from "@projectcaluma/ember-distribution/gql/queries/incomplete-inquiries.graphql"; export default class CdNavigationControlsComponent extends Component { @@ -76,7 +76,7 @@ export default class CdNavigationControlsComponent extends Component { ); yield this.apollo.mutate({ - mutation: redoWorkItemMutation, + mutation: reopenDistributionMutation, variables: { workItem: distributionWorkItemId, }, diff --git a/packages/distribution/addon/gql/fragments/inquiry.graphql b/packages/distribution/addon/gql/fragments/inquiry.graphql index 86c6134eb..b3a8df84b 100644 --- a/packages/distribution/addon/gql/fragments/inquiry.graphql +++ b/packages/distribution/addon/gql/fragments/inquiry.graphql @@ -67,6 +67,7 @@ fragment InquiryDialog on WorkItem { createdAt closedAt status + isRedoable task { id slug diff --git a/packages/distribution/addon/gql/mutations/complete-inquiry-work-item.graphql b/packages/distribution/addon/gql/mutations/complete-inquiry-work-item.graphql index 7c4ea2a78..7a00df92e 100644 --- a/packages/distribution/addon/gql/mutations/complete-inquiry-work-item.graphql +++ b/packages/distribution/addon/gql/mutations/complete-inquiry-work-item.graphql @@ -29,6 +29,7 @@ mutation CompleteInquiryWorkItem( parentWorkItem { id status + isRedoable } } } diff --git a/packages/distribution/addon/gql/mutations/redo-work-item.graphql b/packages/distribution/addon/gql/mutations/reopen-distribution.graphql similarity index 67% rename from packages/distribution/addon/gql/mutations/redo-work-item.graphql rename to packages/distribution/addon/gql/mutations/reopen-distribution.graphql index d0559a4c7..945e97143 100644 --- a/packages/distribution/addon/gql/mutations/redo-work-item.graphql +++ b/packages/distribution/addon/gql/mutations/reopen-distribution.graphql @@ -1,4 +1,4 @@ -mutation RedoWorkItem($workItem: ID!) { +mutation ReopenDistribution($workItem: ID!) { redoWorkItem(input: { id: $workItem }) { workItem { id diff --git a/packages/distribution/addon/gql/mutations/reopen-inquiry.graphql b/packages/distribution/addon/gql/mutations/reopen-inquiry.graphql new file mode 100644 index 000000000..c97876d88 --- /dev/null +++ b/packages/distribution/addon/gql/mutations/reopen-inquiry.graphql @@ -0,0 +1,33 @@ +#import InquiryStatusDocument from '../fragments/inquiry.graphql' + +mutation ReopenInquiry( + $workItem: ID! + $statusQuestion: ID! + $buttonTasks: [String]! +) { + redoWorkItem(input: { id: $workItem }) { + workItem { + id + status + isRedoable + childCase { + id + document { + id + ...InquiryStatusDocument + } + workItems(filter: [{ tasks: $buttonTasks }, { status: READY }]) { + edges { + node { + id + task { + id + slug + } + } + } + } + } + } + } +} diff --git a/packages/distribution/tests/integration/components/cd-inquiry-dialog-test.js b/packages/distribution/tests/integration/components/cd-inquiry-dialog-test.js index c337ea9fb..17a87d8d5 100644 --- a/packages/distribution/tests/integration/components/cd-inquiry-dialog-test.js +++ b/packages/distribution/tests/integration/components/cd-inquiry-dialog-test.js @@ -130,4 +130,38 @@ module("Integration | Component | cd-inquiry-dialog", function (hooks) { assert.verifySteps(["transition"]); }); + + test("it can reopen an inquiry", async function (assert) { + assert.expect(6); + + const inquiry = confirmInquiry({ + inquiry: answerInquiry(this.server, { + inquiry: sendInquiry(this.server, { + inquiry: createInquiry(this.server, this.distributionCase, { + from: { id: "group2" }, + to: { id: "group1" }, + }), + }), + }), + }); + + assert.strictEqual(inquiry.status, "COMPLETED"); + + await render( + hbs`` + ); + + this.owner.lookup("service:router").transitionTo = (route, id) => { + assert.strictEqual(route, "inquiry.detail.answer"); + assert.strictEqual(id, inquiry.id); + assert.step("transition"); + }; + + await click("[data-test-reopen]"); + await confirm(); + + assert.strictEqual(inquiry.status, "READY"); + + assert.verifySteps(["transition"]); + }); }); diff --git a/packages/distribution/tests/integration/components/cd-navigation/controls-test.js b/packages/distribution/tests/integration/components/cd-navigation/controls-test.js index 97e1c4989..fe0e3fb06 100644 --- a/packages/distribution/tests/integration/components/cd-navigation/controls-test.js +++ b/packages/distribution/tests/integration/components/cd-navigation/controls-test.js @@ -95,7 +95,7 @@ module("Integration | Component | cd-navigation/controls", function (hooks) { ); }); - test("it can redo the current distribution", async function (assert) { + test("it can reopen the current distribution", async function (assert) { await assert.expect(3); await render(hbs``); diff --git a/packages/distribution/translations/de.yaml b/packages/distribution/translations/de.yaml index bf3c744f5..7f6bca5b8 100644 --- a/packages/distribution/translations/de.yaml +++ b/packages/distribution/translations/de.yaml @@ -85,3 +85,8 @@ caluma: confirm: "Wollen Sie die Anfrage wirklich zurückziehen?" error: "Fehler beim Zurückziehen der Anfrage" status: "Zurückgezogen" + + reopen-inquiry: + link: "Wiedereröffnen" + confirm: "Wollen Sie die Anfrage wirklich wiedereröffnen?" + error: "Fehler beim Wiedereröffnen der Anfrage" diff --git a/packages/distribution/translations/en.yaml b/packages/distribution/translations/en.yaml index e2900b843..3b92533a6 100644 --- a/packages/distribution/translations/en.yaml +++ b/packages/distribution/translations/en.yaml @@ -86,3 +86,8 @@ caluma: confirm: "Do you really want to withdraw the inquiry?" error: "Error while withdrawing the inquiry" status: "Withdrawn" + + reopen-inquiry: + link: "Reopen" + confirm: "Do you really want to reopen the inquiry?" + error: "Error while reopening the inquiry" diff --git a/packages/distribution/translations/fr.yaml b/packages/distribution/translations/fr.yaml index ba9949a56..80d8f32bb 100644 --- a/packages/distribution/translations/fr.yaml +++ b/packages/distribution/translations/fr.yaml @@ -85,3 +85,8 @@ caluma: confirm: "Voulez-vous vraiment retirer la demande ?" error: "Erreur lors du retrait de la demande" status: "Retirée" + + reopen-inquiry: + link: "Rouvrir" + confirm: "Voulez-vous vraiment rouvrir la demande ?" + error: "Erreur lors de la réouverture de la demande" diff --git a/packages/testing/addon/mirage-graphql/mocks/work-item.js b/packages/testing/addon/mirage-graphql/mocks/work-item.js index 57875a442..c8f38900f 100644 --- a/packages/testing/addon/mirage-graphql/mocks/work-item.js +++ b/packages/testing/addon/mirage-graphql/mocks/work-item.js @@ -31,16 +31,21 @@ export default class WorkItemMock extends BaseMock { handleRedoWorkItem(_, { input }) { const { id } = deserialize(input); const workItem = this.collection.find(id); + const caseId = workItem?.childCaseId; if (workItem.taskId === "distribution") { - const caseId = workItem.childCaseId; - this.collection .where({ caseId, taskId: "complete-distribution" }) .update({ status: "READY" }); this.collection .where({ caseId, taskId: "create-inquiry" }) .update({ status: "READY" }); + } else if (workItem.taskId === "inquiry") { + this.server.create("work-item", { + caseId, + status: "READY", + taskId: "adjust-inquiry-answer", + }); } return this.handleSavePayload.fn.call(this, _, { @@ -81,7 +86,7 @@ export default class WorkItemMock extends BaseMock { .update({ status: "CANCELED" }); this.collection .findBy({ childCaseId: caseId }) - .update({ status: "COMPLETED" }); + .update({ status: "COMPLETED", isRedoable: true }); this.schema.cases.find(caseId).update({ status: "COMPLETED" }); } else if (taskId === "revise-inquiry-answer") { this.collection diff --git a/packages/testing/addon/scenarios/distribution.js b/packages/testing/addon/scenarios/distribution.js index 6e92f2516..42190a72f 100644 --- a/packages/testing/addon/scenarios/distribution.js +++ b/packages/testing/addon/scenarios/distribution.js @@ -193,7 +193,7 @@ export function answerInquiry(server, { inquiry, status, reason, hint }) { } export function confirmInquiry({ inquiry }) { - inquiry.update({ status: "COMPLETED" }); + inquiry.update({ status: "COMPLETED", isRedoable: true }); inquiry.childCase.update({ status: "COMPLETED", closedAt: faker.date.recent(),