fix for ThirdParty create flow.

- Added `parent` property handling in `ThirdPartyEdit.vue`, `Create.vue`, and related components for better association with parent entities.
- Updated `Thirdparty` and `ThirdPartyWrite` types to include `parent` property and ensure type safety.
- Adjusted translations and messages to reflect the new parent entity association concept.
This commit is contained in:
2025-10-24 16:20:58 +02:00
parent 4234377b7e
commit 71e146e4f0
6 changed files with 111 additions and 86 deletions

View File

@@ -43,6 +43,7 @@
v-if="type === 'thirdparty'"
:action="action"
:query="query"
:parent="parent"
ref="castThirdparty"
@onThirdPartyCreated="onThirdPartyCreated"
type=""

View File

@@ -53,6 +53,7 @@ defineExpose({ save });
:allowedTypes="props.allowedTypes"
:action="props.action"
:query="props.query"
:parent="props.parent"
@onPersonCreated="onPersonCreated"
@onThirdPartyCreated="onThirdPartyCreated"
></Create>

View File

@@ -2,7 +2,7 @@ import {
Address,
Center,
Civility,
DateTime,
DateTime, SetCivility,
User,
} from "ChillMainAssets/types";
@@ -15,6 +15,7 @@ export interface BaseThirdParty {
acronym: string | null;
active: boolean;
address: Address | null;
contactDataAnonymous: boolean;
createdAt: DateTime;
createdBy: User | null;
email: string | null;
@@ -22,6 +23,7 @@ export interface BaseThirdParty {
id: number;
nameCompany: string | null;
telephone: string | null;
telephone2: string | null;
updatedAt: DateTime | null;
updatedBy: User | null;
}
@@ -50,7 +52,7 @@ export interface ThirdpartyChild extends BaseThirdParty {
kind: "child";
civility: Civility | null;
contactDataAnonymous: boolean;
parent: Thirdparty | null;
parent: ThirdpartyCompany;
profession: string;
firstname: string;
/**
@@ -109,10 +111,15 @@ export interface ThirdpartyCategory {
};
}
export interface SetThirdParty {
readonly type: "thirdparty";
id: number;
}
export interface ThirdPartyWrite {
readonly type: "thirdparty";
kind: ThirdPartyKind;
civility: Civility | null;
civility: SetCivility | null;
profession: string;
firstname: string;
/**
@@ -126,4 +133,5 @@ export interface ThirdPartyWrite {
address_id: number;
}
comment: string;
parent: SetThirdParty|null;
}

View File

@@ -5,7 +5,7 @@
<div class="item-col">
<div class="entity-label">
<div :class="'denomination h' + options.hLevel">
<a v-if="this.options.addLink === true" href="#">
<a v-if="options.addLink === true" href="#">
<span class="name">{{ thirdparty.text }}</span>
</a>
<span class="name" v-else>{{ thirdparty.text }}</span>
@@ -27,7 +27,7 @@
/>
</div>
<p v-if="this.options.addInfo === true" class="moreinfo" />
<p v-if="options.addInfo === true" class="moreinfo" />
</div>
</div>
@@ -44,13 +44,13 @@
<span>{{ getProfession[0] }}</span>
</p>
</li>
<li v-if="hasParent">
<li v-if="isThirdpartyChild(props.thirdparty)">
<i class="fa fa-li fa-hand-o-right" />
<b class="me-2">{{ $t("child_of") }}</b>
<b class="me-2">{{ trans(THIRDPARTY_MESSAGES_CHILD_OF)}}</b>
<on-the-fly
:type="thirdparty.parent.type"
:id="thirdparty.parent.id"
:button-text="thirdparty.parent.text"
:type="props.thirdparty.parent.type"
:id="props.thirdparty.parent.id"
:button-text="props.thirdparty.parent.text"
:display-badge="'true' === 'true'"
action="show"
/>
@@ -128,65 +128,60 @@
</div>
</template>
<script>
<script setup lang="ts">
import { computed, defineAsyncComponent } from "vue";
import AddressRenderBox from "ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue";
import Confidential from "ChillMainAssets/vuejs/_components/Confidential.vue";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import {isThirdpartyChild, isThirdpartyCompany, Thirdparty} from "../../../types";
import {localizeString} from "ChillMainAssets/lib/localizationHelper/localizationHelper";
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
import {
THIRDPARTY_MESSAGES_CHILD_OF,
trans
} from "translator";
export default {
name: "ThirdPartyRenderBox",
components: {
AddressRenderBox,
Confidential,
BadgeEntity,
},
// To avoid components recursively invoking eachother resolve OnTheFly component here
beforeCreate() {
this.$options.components.OnTheFly =
require("ChillMainAssets/vuejs/OnTheFly/components/OnTheFly").default;
},
i18n: {
messages: {
fr: {
children: "Personnes de contact: ",
child_of: "Contact de: ",
},
},
},
props: ["thirdparty", "options"],
computed: {
isMultiline: function () {
if (this.options.isMultiline) {
return this.options.isMultiline;
} else {
return false;
}
},
hasParent() {
return !(
this.thirdparty.parent === null || this.thirdparty.parent === undefined
);
},
getProfession() {
let profession = [];
if (this.hasParent && this.thirdparty.profession) {
profession.push(this.thirdparty.profession);
return profession;
}
// Async to avoid recursive resolution issues
/*
const OnTheFly = defineAsyncComponent(() =>
import("ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue")
);
*/
if (!this.hasParent && this.thirdparty.category) {
profession = this.thirdparty.category.map((category) => category.text);
}
interface RenderOptions {
addInfo?: boolean;
addEntity?: boolean;
addId?: boolean;
addLink?: boolean;
hLevel?: number;
entityDisplayLong?: boolean;
isMultiline?: boolean;
}
return profession;
},
/* TODO need backend normalizer to serve children without circular reference
hasChildren() {
//console.log(this.thirdparty.activeChildren.length > 0)
return false
} */
},
};
const props = defineProps<{ thirdparty: Thirdparty; options: RenderOptions }>();
const isMultiline = computed<boolean>(() => props.options?.isMultiline ?? false);
const hasParent = computed<boolean>(() => {
return isThirdpartyChild(props.thirdparty);
});
const getProfession = computed<string[]>(() => {
const t = props.thirdparty;
const prof: string[] = [];
if (!isThirdpartyCompany(t)) {
prof.push(t.profession);
}
if (!isThirdpartyChild(t)) {
for (const c of t.categories) {
prof.push(localizeString(c.name));
}
}
return prof;
});
</script>
<style lang="scss">

View File

@@ -7,7 +7,7 @@
<span class="chill-entity badge-thirdparty">{{ parent.text }}</span>
</div>
</div>
<div class="form-floating mb-3" v-else-if="kind !== 'child'">
<div class="form-floating mb-3" v-else-if="props.action !== 'addContact'">
<div class="form-check">
<input
class="form-check-input mt-0"
@@ -46,13 +46,9 @@
:options="{
addInfo: true,
addEntity: false,
addAltNames: true,
addId: false,
addLink: false,
addAge: false,
hLevel: 4,
addCenter: false,
addNoData: true,
isMultiline: false,
}"
/>
@@ -64,7 +60,7 @@
<select
class="form-select form-select-lg"
id="civility"
v-model="thirdParty.civility"
v-model="civility"
>
<option selected disabled :value="null">
{{ trans(THIRDPARTY_MESSAGES_THIRDPARTY_CIVILITY) }}
@@ -72,7 +68,7 @@
<option
v-for="civility in civilities"
:key="civility.id"
:value="civility"
:value="civility.id"
>
{{ localizeString(civility.name) }}
</option>
@@ -210,7 +206,7 @@
/>
</div>
<div v-if="parent">
<div v-if="props.action !== 'addContact'">
<div class="input-group mb-3">
<span class="input-group-text" id="comment"
><i class="fa fa-fw fa-pencil"
@@ -249,21 +245,30 @@ import {
createPerson,
getCivilities, WritePersonViolationMap,
} from "ChillPersonAssets/vuejs/_api/OnTheFly";
import {Thirdparty, ThirdPartyKind, ThirdPartyWrite} from "../../../types";
import {Civility} from "ChillMainAssets/types";
import {Thirdparty, ThirdpartyCompany, ThirdPartyKind, ThirdPartyWrite} from "../../../types";
import {Civility, SetCivility} from "ChillMainAssets/types";
import {isValidationException} from "ChillMainAssets/lib/api/apiMethods";
interface ThirdPartyEditProps {
interface ThirdPartyEditWriteProps {
id?: number;
type?: string|null;
action: 'edit' | 'create' | 'addContact';
query?: string|null;
parent?: Thirdparty|null;
type?: 'thirdparty';
action: 'edit' | 'create'
query?: string;
parent?: null;
}
const props = withDefaults(defineProps<ThirdPartyEditProps>(), {type: null, query: null, parent: null});
interface ThirdPartyAddContactProps {
id?: null;
type?: 'thirdparty';
action: 'addContact';
query?: "";
parent: ThirdpartyCompany;
}
type ThirdPartyEditProps = ThirdPartyAddContactProps | ThirdPartyEditWriteProps;
const props = withDefaults(defineProps<ThirdPartyEditProps>(), {type: 'thirdparty', query: "", parent: null});
const emit =
defineEmits<(e: "onThirdPartyCreated", payload: { thirdParty: Thirdparty }) => void>();
@@ -282,6 +287,21 @@ const thirdParty = ref<ThirdPartyWrite>({
telephone: "",
telephone2: "",
comment: "",
parent: null,
});
const civility = computed<number|null>({
get: () => {
if (thirdParty.value.civility !== null) {
return thirdParty.value.civility.id;
}
return null;
},
set: (value: number | null) => {
thirdParty.value.civility =
value !== null ? { id: value, type: "chill_main_civility" } : null;
},
});
const civilities = ref<Civility[]>([])
@@ -352,12 +372,12 @@ onMounted(() => {
getCivilities().then((cv) => {
civilities.value = cv;
});
if (props.action !== "create") {
if (props.action === "edit") {
loadData();
}
if (props.action === 'addContact') {
thirdParty.value.kind = 'child'
thirdParty.value.address = null
} else if (props.action === 'addContact') {
thirdParty.value.kind = 'child';
thirdParty.value.address = null;
thirdParty.value.parent = {id: props.parent.id, type: 'thirdparty'};
}
});

View File

@@ -169,7 +169,7 @@ thirdpartyMessages:
comment: "Commentaire"
profession: "Qualité"
civility: "Civilité"
child_of: "Contact de: "
child_of: "Contact d'une institution"
children: "Personnes de contact: "
thirdparty_duplicate: