From 087b05a0b8e3a9e0279bf59d1dc102a91c75329b Mon Sep 17 00:00:00 2001 From: Viet An Date: Wed, 20 May 2026 15:06:09 +0700 Subject: [PATCH] changes --- app/components/accounting/AccountView.vue | 90 - .../accounting/ConfirmDeleteEntry.vue | 148 -- app/components/accounting/DebtCustomer.vue | 95 -- app/components/accounting/DebtProduct.vue | 95 -- app/components/accounting/DebtView.vue | 643 ------- app/components/accounting/InternalAccount.vue | 51 - app/components/accounting/InternalDeposit.vue | 348 ---- app/components/accounting/InternalEntry.vue | 326 ---- .../accounting/InternalTransfer.vue | 191 --- .../accounting/TransactionInvoice.vue | 344 ---- .../application/CalculationView.vue | 1117 ------------ app/components/application/CommPayment.vue | 161 -- app/components/application/Contract.vue | 286 ---- .../application/ContractPaymentUpload.vue | 556 ------ .../application/PaymentSchedule.vue | 1183 ------------- .../PaymentSchedulePresentation.vue | 798 --------- app/components/application/PhaseAdvance.vue | 1499 ----------------- app/components/common/Notebox.vue | 24 - app/components/common/ProductCountbox.vue | 28 - app/components/debt/Due.vue | 363 ---- app/components/debt/Overdue.vue | 362 ---- app/components/modal/EditDueDateModal.vue | 362 ---- .../modal/PaymentScheduleConfirmModal.vue | 608 ------- app/components/product/Cart.vue | 267 --- app/components/product/Product.vue | 405 ----- app/components/product/ProductView.vue | 1003 ----------- app/components/product/ProjectDocuments.vue | 283 ---- .../transaction/ChangeCustomerModal.vue | 230 --- .../transaction/TransactionConfirmModal.vue | 444 ----- .../transaction/TransactionDetail.vue | 277 --- .../transaction/TransactionFiles.vue | 135 -- .../transaction/TransactionList.vue | 113 -- .../transaction/TransactionPhaseForm.vue | 137 -- .../transaction/TransactionTypeView.vue | 93 - .../transaction/TransactionView.vue | 1253 -------------- app/composables/useAdvancedWorkflow.ts | 398 ----- app/composables/usePaymentCalculator.js | 276 --- app/plugins/02-connection.js | 7 +- app/plugins/04-components.js | 39 +- app/stores/index.js | 2 +- 40 files changed, 5 insertions(+), 15035 deletions(-) delete mode 100644 app/components/accounting/AccountView.vue delete mode 100644 app/components/accounting/ConfirmDeleteEntry.vue delete mode 100644 app/components/accounting/DebtCustomer.vue delete mode 100644 app/components/accounting/DebtProduct.vue delete mode 100644 app/components/accounting/DebtView.vue delete mode 100644 app/components/accounting/InternalAccount.vue delete mode 100644 app/components/accounting/InternalDeposit.vue delete mode 100644 app/components/accounting/InternalEntry.vue delete mode 100644 app/components/accounting/InternalTransfer.vue delete mode 100644 app/components/accounting/TransactionInvoice.vue delete mode 100644 app/components/application/CalculationView.vue delete mode 100644 app/components/application/CommPayment.vue delete mode 100644 app/components/application/Contract.vue delete mode 100644 app/components/application/ContractPaymentUpload.vue delete mode 100644 app/components/application/PaymentSchedule.vue delete mode 100644 app/components/application/PaymentSchedulePresentation.vue delete mode 100644 app/components/application/PhaseAdvance.vue delete mode 100644 app/components/common/Notebox.vue delete mode 100644 app/components/common/ProductCountbox.vue delete mode 100644 app/components/debt/Due.vue delete mode 100644 app/components/debt/Overdue.vue delete mode 100644 app/components/modal/EditDueDateModal.vue delete mode 100644 app/components/modal/PaymentScheduleConfirmModal.vue delete mode 100644 app/components/product/Cart.vue delete mode 100644 app/components/product/Product.vue delete mode 100644 app/components/product/ProductView.vue delete mode 100644 app/components/product/ProjectDocuments.vue delete mode 100644 app/components/transaction/ChangeCustomerModal.vue delete mode 100644 app/components/transaction/TransactionConfirmModal.vue delete mode 100644 app/components/transaction/TransactionDetail.vue delete mode 100644 app/components/transaction/TransactionFiles.vue delete mode 100644 app/components/transaction/TransactionList.vue delete mode 100644 app/components/transaction/TransactionPhaseForm.vue delete mode 100644 app/components/transaction/TransactionTypeView.vue delete mode 100644 app/components/transaction/TransactionView.vue delete mode 100644 app/composables/useAdvancedWorkflow.ts delete mode 100644 app/composables/usePaymentCalculator.js diff --git a/app/components/accounting/AccountView.vue b/app/components/accounting/AccountView.vue deleted file mode 100644 index 623cbed..0000000 --- a/app/components/accounting/AccountView.vue +++ /dev/null @@ -1,90 +0,0 @@ - - diff --git a/app/components/accounting/ConfirmDeleteEntry.vue b/app/components/accounting/ConfirmDeleteEntry.vue deleted file mode 100644 index ee854e1..0000000 --- a/app/components/accounting/ConfirmDeleteEntry.vue +++ /dev/null @@ -1,148 +0,0 @@ - - - diff --git a/app/components/accounting/DebtCustomer.vue b/app/components/accounting/DebtCustomer.vue deleted file mode 100644 index c9cce96..0000000 --- a/app/components/accounting/DebtCustomer.vue +++ /dev/null @@ -1,95 +0,0 @@ - - diff --git a/app/components/accounting/DebtProduct.vue b/app/components/accounting/DebtProduct.vue deleted file mode 100644 index 67d6087..0000000 --- a/app/components/accounting/DebtProduct.vue +++ /dev/null @@ -1,95 +0,0 @@ - - diff --git a/app/components/accounting/DebtView.vue b/app/components/accounting/DebtView.vue deleted file mode 100644 index 3cd8385..0000000 --- a/app/components/accounting/DebtView.vue +++ /dev/null @@ -1,643 +0,0 @@ - - - - - diff --git a/app/components/accounting/InternalAccount.vue b/app/components/accounting/InternalAccount.vue deleted file mode 100644 index 4b8f8b8..0000000 --- a/app/components/accounting/InternalAccount.vue +++ /dev/null @@ -1,51 +0,0 @@ - - diff --git a/app/components/accounting/InternalDeposit.vue b/app/components/accounting/InternalDeposit.vue deleted file mode 100644 index c20140b..0000000 --- a/app/components/accounting/InternalDeposit.vue +++ /dev/null @@ -1,348 +0,0 @@ - - diff --git a/app/components/accounting/InternalEntry.vue b/app/components/accounting/InternalEntry.vue deleted file mode 100644 index d1faccd..0000000 --- a/app/components/accounting/InternalEntry.vue +++ /dev/null @@ -1,326 +0,0 @@ - - - - diff --git a/app/components/accounting/InternalTransfer.vue b/app/components/accounting/InternalTransfer.vue deleted file mode 100644 index da32b8e..0000000 --- a/app/components/accounting/InternalTransfer.vue +++ /dev/null @@ -1,191 +0,0 @@ - - diff --git a/app/components/accounting/TransactionInvoice.vue b/app/components/accounting/TransactionInvoice.vue deleted file mode 100644 index 7bee486..0000000 --- a/app/components/accounting/TransactionInvoice.vue +++ /dev/null @@ -1,344 +0,0 @@ - - - - - diff --git a/app/components/application/CalculationView.vue b/app/components/application/CalculationView.vue deleted file mode 100644 index c4e0214..0000000 --- a/app/components/application/CalculationView.vue +++ /dev/null @@ -1,1117 +0,0 @@ - - - - - diff --git a/app/components/application/CommPayment.vue b/app/components/application/CommPayment.vue deleted file mode 100644 index 8cc17d6..0000000 --- a/app/components/application/CommPayment.vue +++ /dev/null @@ -1,161 +0,0 @@ - - diff --git a/app/components/application/Contract.vue b/app/components/application/Contract.vue deleted file mode 100644 index 96f0078..0000000 --- a/app/components/application/Contract.vue +++ /dev/null @@ -1,286 +0,0 @@ - - - - - diff --git a/app/components/application/ContractPaymentUpload.vue b/app/components/application/ContractPaymentUpload.vue deleted file mode 100644 index ee081fe..0000000 --- a/app/components/application/ContractPaymentUpload.vue +++ /dev/null @@ -1,556 +0,0 @@ - - - - - diff --git a/app/components/application/PaymentSchedule.vue b/app/components/application/PaymentSchedule.vue deleted file mode 100644 index 51bbe12..0000000 --- a/app/components/application/PaymentSchedule.vue +++ /dev/null @@ -1,1183 +0,0 @@ - - - - - diff --git a/app/components/application/PaymentSchedulePresentation.vue b/app/components/application/PaymentSchedulePresentation.vue deleted file mode 100644 index 4c3fd89..0000000 --- a/app/components/application/PaymentSchedulePresentation.vue +++ /dev/null @@ -1,798 +0,0 @@ - - - - - diff --git a/app/components/application/PhaseAdvance.vue b/app/components/application/PhaseAdvance.vue deleted file mode 100644 index 50ce9a0..0000000 --- a/app/components/application/PhaseAdvance.vue +++ /dev/null @@ -1,1499 +0,0 @@ - - - - - diff --git a/app/components/common/Notebox.vue b/app/components/common/Notebox.vue deleted file mode 100644 index b445665..0000000 --- a/app/components/common/Notebox.vue +++ /dev/null @@ -1,24 +0,0 @@ - - diff --git a/app/components/common/ProductCountbox.vue b/app/components/common/ProductCountbox.vue deleted file mode 100644 index 6f83e02..0000000 --- a/app/components/common/ProductCountbox.vue +++ /dev/null @@ -1,28 +0,0 @@ - - diff --git a/app/components/debt/Due.vue b/app/components/debt/Due.vue deleted file mode 100644 index d227efa..0000000 --- a/app/components/debt/Due.vue +++ /dev/null @@ -1,363 +0,0 @@ - - diff --git a/app/components/debt/Overdue.vue b/app/components/debt/Overdue.vue deleted file mode 100644 index f5c5be9..0000000 --- a/app/components/debt/Overdue.vue +++ /dev/null @@ -1,362 +0,0 @@ - - diff --git a/app/components/modal/EditDueDateModal.vue b/app/components/modal/EditDueDateModal.vue deleted file mode 100644 index 34d1518..0000000 --- a/app/components/modal/EditDueDateModal.vue +++ /dev/null @@ -1,362 +0,0 @@ - - - - - diff --git a/app/components/modal/PaymentScheduleConfirmModal.vue b/app/components/modal/PaymentScheduleConfirmModal.vue deleted file mode 100644 index 1c2025b..0000000 --- a/app/components/modal/PaymentScheduleConfirmModal.vue +++ /dev/null @@ -1,608 +0,0 @@ - - - diff --git a/app/components/product/Cart.vue b/app/components/product/Cart.vue deleted file mode 100644 index c49eefc..0000000 --- a/app/components/product/Cart.vue +++ /dev/null @@ -1,267 +0,0 @@ - - - diff --git a/app/components/product/Product.vue b/app/components/product/Product.vue deleted file mode 100644 index 97af258..0000000 --- a/app/components/product/Product.vue +++ /dev/null @@ -1,405 +0,0 @@ - - - diff --git a/app/components/product/ProductView.vue b/app/components/product/ProductView.vue deleted file mode 100644 index 00c5259..0000000 --- a/app/components/product/ProductView.vue +++ /dev/null @@ -1,1003 +0,0 @@ - - - - - diff --git a/app/components/product/ProjectDocuments.vue b/app/components/product/ProjectDocuments.vue deleted file mode 100644 index 29065ac..0000000 --- a/app/components/product/ProjectDocuments.vue +++ /dev/null @@ -1,283 +0,0 @@ - - diff --git a/app/components/transaction/ChangeCustomerModal.vue b/app/components/transaction/ChangeCustomerModal.vue deleted file mode 100644 index a2f7f9c..0000000 --- a/app/components/transaction/ChangeCustomerModal.vue +++ /dev/null @@ -1,230 +0,0 @@ - - - diff --git a/app/components/transaction/TransactionConfirmModal.vue b/app/components/transaction/TransactionConfirmModal.vue deleted file mode 100644 index 1cfa588..0000000 --- a/app/components/transaction/TransactionConfirmModal.vue +++ /dev/null @@ -1,444 +0,0 @@ - - - diff --git a/app/components/transaction/TransactionDetail.vue b/app/components/transaction/TransactionDetail.vue deleted file mode 100644 index f9900e6..0000000 --- a/app/components/transaction/TransactionDetail.vue +++ /dev/null @@ -1,277 +0,0 @@ - - - - diff --git a/app/components/transaction/TransactionFiles.vue b/app/components/transaction/TransactionFiles.vue deleted file mode 100644 index cbccdb3..0000000 --- a/app/components/transaction/TransactionFiles.vue +++ /dev/null @@ -1,135 +0,0 @@ - - - diff --git a/app/components/transaction/TransactionList.vue b/app/components/transaction/TransactionList.vue deleted file mode 100644 index 2daaefa..0000000 --- a/app/components/transaction/TransactionList.vue +++ /dev/null @@ -1,113 +0,0 @@ - - diff --git a/app/components/transaction/TransactionPhaseForm.vue b/app/components/transaction/TransactionPhaseForm.vue deleted file mode 100644 index 453eee2..0000000 --- a/app/components/transaction/TransactionPhaseForm.vue +++ /dev/null @@ -1,137 +0,0 @@ - - - diff --git a/app/components/transaction/TransactionTypeView.vue b/app/components/transaction/TransactionTypeView.vue deleted file mode 100644 index 0e9ac08..0000000 --- a/app/components/transaction/TransactionTypeView.vue +++ /dev/null @@ -1,93 +0,0 @@ - - diff --git a/app/components/transaction/TransactionView.vue b/app/components/transaction/TransactionView.vue deleted file mode 100644 index 4f6ae18..0000000 --- a/app/components/transaction/TransactionView.vue +++ /dev/null @@ -1,1253 +0,0 @@ - - - diff --git a/app/composables/useAdvancedWorkflow.ts b/app/composables/useAdvancedWorkflow.ts deleted file mode 100644 index fc472bd..0000000 --- a/app/composables/useAdvancedWorkflow.ts +++ /dev/null @@ -1,398 +0,0 @@ -import { ref } from "vue"; -import { useNuxtApp } from "#app"; -import dayjs from "dayjs"; - -// Interface cho các tham số từ UI -interface TransactionParams { - product: any; - customer: any; - policy: any; - phaseInfo: any; - priceAfterDiscount: number; - discountValue: number; - detailedDiscounts: any[]; - paymentPlans: any[]; - currentDate: string; - reservationDueDate: string; - reservationAmount: number; - depositReceived: number; - people?: number | null; - earlyDiscountAmount?: number; - gifts?: Array<{ id: number }>; // Thêm trường gifts -} - -export function useAdvancedWorkflow() { - const { $insertapi, $snackbar, $store } = useNuxtApp(); - const isLoading = ref(false); - const error = ref(null); - - /** - * Helper: Tìm kết quả của một step cụ thể trong mảng 'result' của backend trả về - */ - const findStepResult = (steps: any[], stepCode: string, filter?: string | ((res: any) => boolean)) => { - if (!Array.isArray(steps)) return null; - - // 1. Tìm đúng step đang thực thi - const step = steps.find((s) => (s.step === stepCode || s.step?.startsWith(stepCode)) && s.executed); - if (!step || !Array.isArray(step.results) || step.results.length === 0) return null; - - // 2. Nếu filter là một hàm (Callback) - if (typeof filter === "function") { - const matched = step.results.find(filter); - return matched ? matched.result : null; - } - - // 3. Nếu filter là một chuỗi (Action Name) - if (typeof filter === "string") { - const matched = step.results.find((r) => r.action === filter); - return matched ? matched.result : null; - } - - // 4. Mặc định: Trả về result của phần tử đầu tiên - return step.results[0]?.result; - }; - - /** - * Chuyển đổi danh sách chiết khấu sang format API - */ - const mapDiscountsList = (detailedDiscounts: any[]) => { - if (!detailedDiscounts) return []; - return detailedDiscounts - .filter((d) => d.id) - .map((d) => ({ - discount: d.id, - value: d.customValue, - type: d.customType, - })); - }; - - /** - * Tạo lịch thanh toán cọc (Installments) - */ - const createInstallments = (depositReceived: number, reservationAmount: number) => { - const installments = []; - if (depositReceived > 0) { - installments.push({ - amount: depositReceived, - due_days: 0, - description: "Thanh toán tiền đặt cọc đã nhận", - detail: { note: "Thanh toán tiền đặt cọc" }, - }); - } - - const remaining = reservationAmount - depositReceived; - if (remaining > 0) { - installments.push({ - amount: remaining, - due_days: 2, - description: "Phần cọc còn lại", - detail: { note: "Thanh toán phần cọc còn lại" }, - }); - } - return installments; - }; - - const createWorkflowTransaction = async (params: TransactionParams) => { - isLoading.value = true; - error.value = null; - - try { - const userId = $store?.login?.id; - if (!userId) { - throw new Error("Không tìm thấy thông tin người dùng. Vui lòng đăng nhập lại."); - } - - // 1. Cấu hình Body theo đúng workflow - const workflowPayload = { - workflow_code: "FULL_CONTRACT_CREATION", - trigger: "create", - data: { - phase_code: params.phaseInfo.code, - current_date: params.currentDate, - due_date: params.reservationDueDate, - customer_id: params.customer.id, - product_id: params.product.id, - policy_id: params.policy.id, - user_id: userId, - sale_price: params.product.origin_price, - origin_price: params.product.origin_price, - deposit_amount: params.reservationAmount, - discount_amount: 0, - amount_received: 0, - payment_plan: params.paymentPlans, - installments: createInstallments(params.depositReceived, params.reservationAmount), - people: params.people || null, - early_discount_amount: Math.trunc(params.earlyDiscountAmount || 0), - gifts: params.gifts || [], // Thêm danh sách quà tặng - }, - }; - - // 2. Gọi API Workflow - const response = await $insertapi("workflow", workflowPayload, undefined, false); - - // Kiểm tra thành công - if (response === "error" || !response?.success) { - throw new Error(response?.message || "Thực thi Workflow thất bại."); - } - - // 3. Bóc tách dữ liệu từ mảng result trả về - const steps = response.result; - - // Lấy Transaction từ step "create_transaction" với action "API_CALL" - const txnData = findStepResult(steps, "create_transaction", "API_CALL"); - - console.log("Transaction Data:", txnData); - - $snackbar("Giao dịch đã được khởi tạo thành công!", "Thành công", "Success"); - - // 4. Return transaction data - return { - transaction: txnData ? { id: txnData.id, code: txnData.code } : null, - }; - } catch (e: any) { - error.value = e; - console.error("Workflow Error:", e); - $snackbar(e.message || "Có lỗi xảy ra khi thực thi workflow.", "Lỗi", "Error"); - return null; - } finally { - isLoading.value = false; - } - }; - - /** - * DUYỆT CÔNG NỢ (KẾ TOÁN) - SỬ DỤNG WORKFLOW - */ - const confirmPaymentSchedule = async (paymentId: number, payload?: object): Promise => { - isLoading.value = true; - error.value = null; - - try { - const userId = $store?.login?.id; - if (!userId) { - throw new Error("Không tìm thấy thông tin người dùng. Vui lòng đăng nhập lại."); - } - - const workflowPayload = { - workflow_id: 9, - workflow_code: "APPROVE_PAYMENT", - trigger: "create", - data: { - payment_id: paymentId, - user_id: userId, - ...payload, - }, - }; - - const response = await $insertapi("workflow", workflowPayload, undefined, false); - - if (response === "error" || !response?.success) { - throw new Error(response?.message || "Không thể xác nhận công nợ qua workflow."); - } - - $snackbar("Công nợ đã được xác nhận thành công!", "Thành công", "Success"); - return true; - } catch (e: any) { - error.value = e; - console.error("Workflow Error (confirmPaymentSchedule):", e); - $snackbar(e.message || "Có lỗi xảy ra khi xác nhận công nợ.", "Lỗi", "Error"); - return false; - } finally { - isLoading.value = false; - } - }; - - const rollbackPayment = async (paymentId: number, entryCode: string, entryAmount: number) => { - isLoading.value = true; - error.value = null; - - try { - const userId = $store?.login?.id; - if (!userId) { - throw new Error("Không tìm thấy thông tin người dùng. Vui lòng đăng nhập lại."); - } - - const workflowPayload = { - workflow_code: "ROLLBACK_PAYMENT", - trigger: "create", - data: { - payment_id: paymentId, - entry_code: entryCode, - amount: entryAmount, - }, - }; - - const response = await $insertapi("workflow", workflowPayload, undefined, false); - - if (response === "error" || !response?.success) { - throw new Error(response?.message || "Không thể hủy bút toán qua workflow."); - } - - $snackbar("Công nợ đã được xác nhận thành công!", "Thành công", "Success"); - return true; - } catch (e: any) { - error.value = e; - console.error("Workflow Error (confirmPaymentSchedule):", e); - $snackbar(e.message || "Có lỗi xảy ra khi xác nhận công nợ.", "Lỗi", "Error"); - return false; - } finally { - isLoading.value = false; - } - }; - - /** - * DUYỆT CHI TIẾT GIAO DỊCH (QUẢN LÝ) - SỬ DỤNG WORKFLOW - */ - const approveTransactionDetail = async (detailId: number, statusCode: string): Promise => { - isLoading.value = true; - error.value = null; - - try { - const userId = $store?.login?.id; - if (!userId) { - throw new Error("Không tìm thấy thông tin người dùng. Vui lòng đăng nhập lại."); - } - - const workflowPayload = { - workflow_code: "APPROVE_TRANSACTION_DETAIL", - trigger: "create", - data: { - detail_id: detailId, - status_code: statusCode, - user_id: userId, - }, - }; - - const response = await $insertapi("workflow", workflowPayload, undefined, false); - - if (response === "error" || !response?.success) { - throw new Error(response?.message || "Không thể duyệt chi tiết giao dịch qua workflow."); - } - - $snackbar("Chi tiết giao dịch đã được duyệt thành công!", "Thành công", "Success"); - return response; - } catch (e: any) { - error.value = e; - console.error("Workflow Error (approveTransactionDetail):", e); - $snackbar(e.message || "Có lỗi xảy ra khi duyệt chi tiết giao dịch.", "Lỗi", "Error"); - return null; - } finally { - isLoading.value = false; - } - }; - - /** - * CHUYỂN GIAI ĐOẠN GIAO DỊCH - SỬ DỤNG WORKFLOW - */ - const advanceTransactionPhase = async (detailId: number): Promise => { - isLoading.value = true; - error.value = null; - - try { - const userId = $store?.login?.id; - if (!userId) { - throw new Error("Không tìm thấy thông tin người dùng. Vui lòng đăng nhập lại."); - } - - const workflowPayload = { - workflow_code: "ADVANCE_TRANSACTION_PHASE", - trigger: "create", - data: { - detail_id: detailId, - user_id: userId, - }, - }; - - const response = await $insertapi("workflow", workflowPayload, undefined, false); - - if (response === "error" || !response?.success) { - throw new Error(response?.message || "Không thể chuyển giai đoạn giao dịch qua workflow."); - } - - const steps = response.result; - - // 1. Tìm contract thông qua step bắt đầu bằng 'adv_from_phase_' với action là 'GENERATE_DOCUMENT' - const contract = findStepResult(steps, "adv_lookup_transaction", "LOOKUP_DATA"); - - console.log("contract", contract); - - $snackbar("Chuyển giai đoạn giao dịch thành công!", contract, "Success"); - - return { - ...response, - contract: contract, - }; - } catch (e: any) { - error.value = e; - console.error("Workflow Error (advanceTransactionPhase):", e); - $snackbar(e.message || "Có lỗi xảy ra khi chuyển giai đoạn.", "Lỗi", "Error"); - return null; - } finally { - isLoading.value = false; - } - }; - - /** - * CHUYỂN ĐỔI KHÁCH HÀNG - SỬ DỤNG WORKFLOW - */ - const updateTransactionCustomer = async ( - transactionId: number, - newCustomerId: number, - contractDate?: string, - ): Promise => { - isLoading.value = true; - error.value = null; - try { - const userId = $store?.login?.id; - if (!userId) { - throw new Error("Không tìm thấy thông tin người dùng. Vui lòng đăng nhập lại."); - } - - const workflowPayload = { - workflow_code: "UPDATE_TRANS_AND_CO_OP", - trigger: "create", - data: { - transaction: transactionId, - new_cus: newCustomerId, - user_id: userId, - date: contractDate || dayjs().format("YYYY-MM-DD"), - }, - }; - - const response = await $insertapi("workflow", workflowPayload, undefined, false); - - if (response === "error" || !response?.success) { - throw new Error(response?.message || "Không thể chuyển đổi khách hàng qua workflow."); - } - - const steps = response.result; - - // Find the contract from any executed step starting with 'GEN_' - const contract = findStepResult(steps, "GEN_", "API_CALL"); - - $snackbar("Chuyển đổi khách hàng thành công!", "Thành công", "Success"); - - return { - ...response, - contract: contract, - }; - } catch (e: any) { - error.value = e; - console.error("Workflow Error (updateTransactionCustomer):", e); - $snackbar(e.message || "Có lỗi xảy ra khi chuyển đổi khách hàng.", "Lỗi", "Error"); - return null; - } finally { - isLoading.value = false; - } - }; - - return { - isLoading, - error, - createWorkflowTransaction, - confirmPaymentSchedule, - approveTransactionDetail, - advanceTransactionPhase, - updateTransactionCustomer, - rollbackPayment, - }; -} diff --git a/app/composables/usePaymentCalculator.js b/app/composables/usePaymentCalculator.js deleted file mode 100644 index c372d9d..0000000 --- a/app/composables/usePaymentCalculator.js +++ /dev/null @@ -1,276 +0,0 @@ -// composables/usePaymentCalculator.js -import { ref, computed } from "vue"; - -export function usePaymentCalculator() { - // Inputs cơ bản - const originPrice = ref(0); - const discounts = ref([]); // [{ id, name, code, type: 1 (percent) | 2 (fixed), value: number }] - const paymentPlan = ref([]); // [{cycle, value, type: 1 (percent) | other (fixed), days, ...}] - const contractAllocationPercentage = ref(100); - const startDate = ref(new Date()); - - // Thanh toán sớm - const earlyPaymentCycles = ref(0); - const earlyDiscountRate = ref(0.0191780821918); - - // Số tiền đã thanh toán thực tế - const paidAmount = ref(0); - - // Tiền gốc - const originalPrice = computed(() => originPrice.value); - - // Chi tiết chiết khấu - const detailedDiscounts = computed(() => { - const details = []; - let currentBalance = originPrice.value || 0; - - discounts.value.forEach((discountData) => { - const d = discountData; - let amount = 0; - if (d.type === 1) { - // percent - amount = (currentBalance * Number(d.value)) / 100; - } else { - // fixed - amount = Number(d.value); - } - if (currentBalance - amount < 0) { - amount = currentBalance; - } - currentBalance -= amount; - - details.push({ - id: d.id, - name: d.name, - code: d.code, - customValue: d.value, - customType: d.type, - amount: amount, - remaining: currentBalance, - }); - }); - return details; - }); - - // Tổng tiền giảm giá từ discounts - const totalDiscount = computed(() => { - return detailedDiscounts.value.reduce((sum, d) => sum + d.amount, 0); - }); - - // Giá sau chiết khấu - const salePrice = computed(() => { - const lastDiscount = detailedDiscounts.value[detailedDiscounts.value.length - 1]; - return lastDiscount ? lastDiscount.remaining : originPrice.value; - }); - - const allocatedAmount = computed(() => { - const amount = salePrice.value * (contractAllocationPercentage.value / 100); - return Math.round(amount / 1000) * 1000; - }); - - const finalTotal = computed(() => allocatedAmount.value); - - // Lịch thanh toán gốc (hỗ trợ cả percent và fixed cho paymentPlan.type) - const originalPaymentSchedule = computed(() => { - const schedule = []; - let remaining = allocatedAmount.value; - - const sortedPlan = [...paymentPlan.value].sort((a, b) => a.cycle - b.cycle); - - let lastToDateForPeriodCalc = new Date(startDate.value); // Used to calculate the duration of each installment period. - - sortedPlan.forEach((plan) => { - let amount = 0; - - // Xử lý linh hoạt theo type của Payment_Plan - if (plan.type === 1) { - // percent - amount = allocatedAmount.value * (plan.value / 100); - } else { - // fixed (type 2 hoặc bất kỳ giá trị khác) - amount = plan.value || 0; - } - - const adjustedAmount = Math.min(amount, remaining); - remaining -= adjustedAmount; - - const fromDate = new Date(startDate.value); // Per user request, all installments start from the same date. - const toDate = new Date(startDate.value); - toDate.setDate(toDate.getDate() + (plan.days || 0)); - - // The duration of the installment period is the difference between this installment's due date and the previous one. - const daysInPeriod = Math.round((toDate.getTime() - lastToDateForPeriodCalc.getTime()) / (1000 * 60 * 60 * 24)); - - schedule.push({ - cycle: plan.cycle, - from_date: fromDate, - to_date: toDate, - amount: adjustedAmount, - paid_amount: 0, - remain_amount: adjustedAmount, - days: daysInPeriod > 0 ? daysInPeriod : 0, // Use calculated period duration; it cannot be negative. - status: 1, - type: plan.type, - value: plan.value, - payment_note: `Thanh toán theo kế hoạch đợt số ${plan.cycle}`, - }); - - lastToDateForPeriodCalc = new Date(toDate); // Update the last due date for the next period's duration calculation. - }); - - // Cộng phần dư (nếu có) vào đợt cuối - if (remaining > 0 && schedule.length > 0) { - const last = schedule[schedule.length - 1]; - last.amount += remaining; - last.remain_amount += remaining; - } - - return schedule; - }); - - // Chiết khấu thanh toán sớm - const earlyDiscounts = computed(() => { - if (earlyPaymentCycles.value <= 0) return []; - - const schedule = originalPaymentSchedule.value; - const numEarly = Math.min(earlyPaymentCycles.value, schedule.length); - const actualPaymentDate = new Date(startDate.value); - const actualPaymentDateOnly = new Date( - actualPaymentDate.getFullYear(), - actualPaymentDate.getMonth(), - actualPaymentDate.getDate(), - ); - - return schedule.slice(0, numEarly).map((item) => { - const originalDate = new Date(item.to_date); - const originalDateOnly = new Date(originalDate.getFullYear(), originalDate.getMonth(), originalDate.getDate()); - const earlyDays = Math.round( - (originalDateOnly.getTime() - actualPaymentDateOnly.getTime()) / (1000 * 60 * 60 * 24), - ); - - if (earlyDays <= 0) { - return 0; - } - return item.amount * earlyDays * (earlyDiscountRate.value / 100); - }); - }); - - const totalEarlyDiscount = computed(() => { - const rawTotal = earlyDiscounts.value.reduce((sum, disc) => sum + disc, 0); - return parseInt(rawTotal); - }); - - // Chi tiết chiết khấu thanh toán sớm - const earlyDiscountDetails = computed(() => { - if (earlyPaymentCycles.value <= 0) return []; - - const schedule = originalPaymentSchedule.value; - const numEarly = Math.min(earlyPaymentCycles.value, schedule.length); - const actualPaymentDate = new Date(startDate.value); - const actualPaymentDateOnly = new Date( - actualPaymentDate.getFullYear(), - actualPaymentDate.getMonth(), - actualPaymentDate.getDate(), - ); - - return schedule.slice(0, numEarly).map((item, index) => { - const originalDate = new Date(item.to_date); - const originalDateOnly = new Date(originalDate.getFullYear(), originalDate.getMonth(), originalDate.getDate()); - const earlyDays = Math.round( - (originalDateOnly.getTime() - actualPaymentDateOnly.getTime()) / (1000 * 60 * 60 * 24), - ); - - return { - cycle: item.cycle, - original_payment_date: originalDate, - actual_payment_date: actualPaymentDate, - early_days: earlyDays > 0 ? earlyDays : 0, - original_amount: item.amount, - discount_rate: earlyDiscountRate.value, - discount_amount: earlyDiscounts.value[index] || 0, - }; - }); - }); - - // Lịch sau thanh toán sớm (gộp đợt) - const scheduleAfterEarly = computed(() => { - const base = originalPaymentSchedule.value; - const numEarly = Math.min(earlyPaymentCycles.value, base.length); - - if (numEarly <= 0) return base; - - const earlyItems = base.slice(0, numEarly); - const totalEarlyAmount = earlyItems.reduce((sum, i) => sum + i.amount, 0); - const mergedAmount = totalEarlyAmount - totalEarlyDiscount.value; - - const originalCycles = earlyItems.map((i) => i.cycle); - - const mergedItem = { - cycle: 1, - from_date: earlyItems[0].from_date, - to_date: earlyItems[0].from_date, // Due date is the start date for the merged installment - amount: Math.max(0, mergedAmount), - paid_amount: 0, - remain_amount: Math.max(0, mergedAmount), - payment_note: `Thanh toán gộp đợt ${originalCycles.join(", ")} (đã trừ số tiền chiết khấu thanh toán sớm là ${totalEarlyDiscount.value})`, - days: 0, - status: 1, - is_merged: true, - original_cycles: originalCycles, - }; - - const remainingItems = base.slice(numEarly).map((item, idx) => ({ - ...item, - cycle: idx + 2, - })); - - return [mergedItem, ...remainingItems]; - }); - - // Lịch thanh toán cuối cùng - const finalPaymentSchedule = computed(() => { - const schedule = scheduleAfterEarly.value.map((item) => ({ ...item })); - let remainingPaid = paidAmount.value || 0; - - for (let i = 0; i < schedule.length && remainingPaid > 0; i++) { - const item = schedule[i]; - const canPay = Math.min(remainingPaid, item.remain_amount); - - item.paid_amount += canPay; - item.remain_amount -= canPay; - remainingPaid -= canPay; - - if (item.remain_amount <= 0) { - item.status = 2; - item.remain_amount = 0; - } - } - - return schedule; - }); - - const totalRemaining = computed(() => finalPaymentSchedule.value.reduce((sum, item) => sum + item.remain_amount, 0)); - - return { - originPrice, - discounts, - paymentPlan, - contractAllocationPercentage, - startDate, - earlyPaymentCycles, - earlyDiscountRate, - paidAmount, - - originalPrice, - detailedDiscounts, - totalDiscount, - salePrice, - allocatedAmount, - finalTotal, - finalPaymentSchedule, - originalPaymentSchedule, - earlyDiscountDetails, - totalEarlyDiscount, - totalRemaining, - }; -} diff --git a/app/plugins/02-connection.js b/app/plugins/02-connection.js index 36f1550..4a54428 100644 --- a/app/plugins/02-connection.js +++ b/app/plugins/02-connection.js @@ -1,6 +1,6 @@ export default defineNuxtPlugin((nuxtApp) => { const module = "application"; - const mode = "prod"; + const mode = "dev"; const paths = [ { name: "dev", url: "https://erpapi.bigdatatech.vn/" }, { name: "local", url: "http://localhost:8000/" }, @@ -590,10 +590,7 @@ export default defineNuxtPlugin((nuxtApp) => { commit: "productdocument", url: "data/Product_Document/", url_detail: "data-detail/Product_Document/", - params: { - values: - "id,product,product__code,product__type,product__type__code,product__type__name,product__type__en,product__category,product__category__code,product__category__name,document,document__code,document__name,document__en", - }, + params: {}, }, { name: "productstatus", diff --git a/app/plugins/04-components.js b/app/plugins/04-components.js index b3a32d2..02de6f6 100644 --- a/app/plugins/04-components.js +++ b/app/plugins/04-components.js @@ -45,8 +45,6 @@ import Customers from "@/components/report/Customers.vue"; import Goods from "@/components/report/Goods.vue"; import ReportCashBook from "@/components/report/CashBook.vue"; import Finance from "@/components/report/Finance.vue"; -import Notebox from "@/components/common/Notebox.vue"; -import ProductCountbox from "@/components/common/ProductCountbox.vue"; import SvgIcon from "@/components/SvgIcon.vue"; import DataView from "@/components/datatable/DataView.vue"; import PivotDataView from "@/components/datatable/PivotDataView.vue"; @@ -61,11 +59,9 @@ import Avatarbox from "@/components/common/Avatarbox.vue"; import Email from "@/components/marketing/email/Email.vue"; import ViewList from "@/components/common/ViewList.vue"; import InternalEntry from "@/components/modal/InternalEntry.vue"; - import Configuration from "@/components/maintab/Configuration.vue"; -import DebtView from "@/components/accounting/DebtView.vue"; -//format +// format import FormatNumber from "@/components/datatable/format/FormatNumber.vue"; import FormatDate from "@/components/datatable/format/FormatDate.vue"; import DataTable from "@/components/datatable/DataTable.vue"; @@ -73,7 +69,7 @@ import DataModel from "@/components/datatable/DataModel.vue"; import InputNumber from "@/components/common/InputNumber.vue"; import ColorText from "@/components/datatable/format/ColorText.vue"; -//menu +// menu import MenuAction from "@/components/menu/MenuAction.vue"; import MenuApp from "@/components/menu/MenuApp.vue"; import MenuCust from "@/components/menu/MenuCust.vue"; @@ -84,48 +80,25 @@ import MenuCollab from "@/components/menu/MenuCollab.vue"; import MenuNote from "@/components/menu/MenuNote.vue"; import MenuPayment from "@/components/menu/MenuPayment.vue"; import ScrollBox from "@/components/datatable/ScrollBox.vue"; -import Product from "@/components/product/Product.vue"; import Reservation from "@/components/modal/Reservation.vue"; import UserMainTab from "@/components/modal/UserMainTab.vue"; -import TransactionFiles from "@/components/transaction/TransactionFiles.vue"; -import PaymentSchedule from "@/components/application/PaymentSchedule.vue"; -import TransactionView from "@/components/transaction/TransactionView.vue"; -import ContractPaymentUpload from "@/components/application/ContractPaymentUpload.vue"; import CountWithAdd from "@/components/common/CountWithAdd.vue"; -import CalculationView from "@/components/application/CalculationView.vue"; -import InternalAccount from "@/components/accounting/InternalAccount.vue"; import MenuAccount from "@/components/menu/MenuAccount.vue"; -import PhaseAdvance from "@/components/application/PhaseAdvance.vue"; import ImageLayout from "@/components/media/ImageLayout.vue"; -import ProjectDocuments from "@/components/product/ProjectDocuments.vue"; -import Cart from "@/components/product/Cart.vue"; import CountdownTimer from "@/components/common/CountdownTimer.vue"; import CustomerInfo2 from "@/components/customer/CustomerInfo2.vue"; import MenuFile from "@/components/menu/MenuFile.vue"; -import DebtProduct from "@/components/accounting/DebtProduct.vue"; -import DebtCustomer from "@/components/accounting/DebtCustomer.vue"; -import Due from "@/components/debt/Due.vue"; -import Overdue from "@/components/debt/Overdue.vue"; const components = { - DebtView, PivotDataView, - PaymentSchedule, CustomerInfo2, CountdownTimer, - PhaseAdvance, InternalEntry, ViewList, ColorText, - CalculationView, CountWithAdd, - ContractPaymentUpload, - TransactionView, - TransactionFiles, Reservation, - Notebox, - ProductCountbox, MenuAction, Email, SvgIcon, @@ -153,18 +126,10 @@ const components = { MenuAdd, MenuCollab, MenuNote, - Product, UserMainTab, - InternalAccount, MenuAccount, ImageLayout, - ProjectDocuments, - Cart, MenuFile, - DebtProduct, - DebtCustomer, - Due, - Overdue, Dashboard, Orders, Inventory, diff --git a/app/stores/index.js b/app/stores/index.js index b13438b..3552b08 100644 --- a/app/stores/index.js +++ b/app/stores/index.js @@ -1,6 +1,6 @@ import { defineStore } from "pinia"; -export const useStore = defineStore("main", { +export const useStore = defineStore("maindev", { state: () => ({ viewport: undefined, login: undefined,