diff --git a/src/pages/05_quotation/MainPage.vue b/src/pages/05_quotation/MainPage.vue
index 654efc25..d5e53ca1 100644
--- a/src/pages/05_quotation/MainPage.vue
+++ b/src/pages/05_quotation/MainPage.vue
@@ -19,6 +19,7 @@ import { CustomerBranchCreate } from 'stores/customer/types';
import { Employee } from 'src/stores/employee/types';
// NOTE: Import Components
+import TreeView from 'src/components/shared/TreeView.vue';
import QuotationCard from 'src/components/05_quotation/QuotationCard.vue';
import PaginationComponent from 'src/components/PaginationComponent.vue';
import StatCardComponent from 'src/components/StatCardComponent.vue';
@@ -26,7 +27,6 @@ import ButtonAddComponent from 'components/ButtonAddCompoent.vue';
import FormAbout from 'src/components/05_quotation/FormAbout.vue';
import SelectZone from 'src/components/shared/SelectZone.vue';
import PersonCard from 'src/components/shared/PersonCard.vue';
-import ProductServiceForm from './ProductServiceForm.vue';
import CreateButton from 'src/components/AddButton.vue';
import ItemCard from 'src/components/ItemCard.vue';
import DialogForm from 'components/DialogForm.vue';
@@ -34,11 +34,6 @@ import { AddButton } from 'src/components/button';
import SideMenu from 'components/SideMenu.vue';
import { dialogCreateCustomerItem } from 'src/pages/03_customer-management/constant';
-import {
- ProductGroup,
- Product,
- Service,
-} from 'src/stores/product-service/types';
import { SaveButton } from 'components/button';
@@ -54,6 +49,7 @@ import {
useEmployeeForm,
} from 'src/pages/03_customer-management/form';
import QuotationView from './QuotationView.vue';
+import { quotationProductTree } from './utils';
const quotationFormStore = useQuotationForm();
const customerFormStore = useCustomerForm();
@@ -633,6 +629,38 @@ watch(() => pageState.currentTab, fetchQuotationList);
/>
+ (
+
+ )
@@ -1056,33 +1084,6 @@ watch(() => pageState.currentTab, fetchQuotationList);
-
- {
- await getAllService(id);
- await getAllProduct(id);
- }
- "
- @submit="
- (node) => {
- const nodeRecursive = (
- v: (typeof node)[number],
- ): typeof node | (typeof node)[number] => {
- if (v.checked && v.children) return v.children.flatMap(nodeRecursive);
- if (v.checked) return v;
- return [];
- };
-
- const filtered = node.flatMap(nodeRecursive);
- console.log(JSON.parse(JSON.stringify(filtered.map((v) => v.value))));
- }
- "
- >
diff --git a/src/pages/05_quotation/utils.ts b/src/pages/05_quotation/utils.ts
new file mode 100644
index 00000000..41a6c31e
--- /dev/null
+++ b/src/pages/05_quotation/utils.ts
@@ -0,0 +1,106 @@
+import { QuotationFull } from 'src/stores/quotations/types';
+
+export type ProductTree = {
+ id: string;
+ title: string;
+ subtitle: string;
+ checked: boolean;
+ opened: boolean;
+ icon: string;
+ fg: string;
+ bg: string;
+ value?: {
+ vat: number;
+ pricePerUnit: number;
+ discount: number;
+ amount: number;
+ serviceId?: string;
+ service?: QuotationFull['productServiceList'][number]['service'];
+ workId: string;
+ work?: QuotationFull['productServiceList'][number]['work'];
+ productId: string;
+ product: QuotationFull['productServiceList'][number]['product'];
+ };
+ children?: ProductTree;
+}[];
+
+export function quotationProductTree(
+ list: {
+ service?: QuotationFull['productServiceList'][number]['service'];
+ work?: QuotationFull['productServiceList'][number]['work'];
+ product: QuotationFull['productServiceList'][number]['product'];
+ }[],
+): ProductTree {
+ const ret: ProductTree = [];
+
+ for (let i = 0; i < list.length; i++) {
+ const current = list[i];
+
+ if (ret.find((v) => v.id === current.service?.id)) continue;
+
+ if (current.service && current.work) {
+ const service = current.service;
+
+ ret.push({
+ id: service.id,
+ title: service.name,
+ subtitle: service.code,
+ opened: service.work.length > 0,
+ checked: true,
+ children: service.work.flatMap((work) => {
+ const mapper = (
+ relation: (typeof work)['productOnWork'][number],
+ ) => ({
+ id: relation.product.id,
+ title: relation.product.name,
+ subtitle: relation.product.code,
+ opened: true,
+ checked: !!list.find(
+ (v) =>
+ v.service?.id === service.id &&
+ v.work?.id === work.id &&
+ v.product.id === relation.product.id,
+ ),
+ icon: 'mdi-shopping-outline',
+ bg: 'hsla(var(--teal-10-hsl)/0.1)',
+ fg: 'var(--teal-10)',
+ });
+
+ if (!!work.name) {
+ return {
+ id: work.id,
+ title: work.name,
+ subtitle: ' ',
+ opened: true,
+ checked: !!list.find(
+ (v) => v.service?.id === service.id && v.work?.id === work.id,
+ ),
+ children: work.productOnWork.map(mapper),
+ icon: 'mdi-briefcase-outline',
+ bg: 'hsla(var(--violet-11-hsl)/0.1)',
+ fg: 'var(--violet-11)',
+ };
+ }
+
+ return work.productOnWork.map(mapper);
+ }),
+ icon: 'mdi-server-outline',
+ bg: 'hsla(var(--orange-5-hsl)/0.1)',
+ fg: 'var(--orange-5)',
+ });
+ } else {
+ ret.push({
+ id: current.product.id,
+ title: current.product.name,
+ subtitle: current.product.code,
+ opened: true,
+ checked: true,
+ icon: 'mdi-shopping-outline',
+ bg: 'hsla(var(--teal-10-hsl)/0.1)',
+ fg: 'var(--teal-10)',
+ });
+ }
+ }
+
+ return ret;
+}
diff --git a/src/stores/quotations/types.ts b/src/stores/quotations/types.ts
index a52f6663..788956c6 100644
--- a/src/stores/quotations/types.ts
+++ b/src/stores/quotations/types.ts
@@ -149,6 +149,13 @@ type ServiceRelation = {
createdByUserId: string;
updatedAt: string;
updatedByUserId: string;
+
+ work: (WorkRelation & {
+ productOnWork: {
+ order: number;
+ product: ProductRelation;
+ }[];
+ })[];
};
export type QuotationStats = {