+
{{ formatNumber(item.totalCustomsCharges) }}
ریال
@@ -128,7 +128,7 @@
@@ -281,13 +281,13 @@ const formatMoney = (value) => {
}
// Computed
-const totalCharges = computed(() => {
+const totalChargesNumeric = computed(() => {
const duty = parseFloat(formData.value.customsDuty) || 0
const vat = parseFloat(formData.value.valueAddedTax) || 0
const other = parseFloat(formData.value.otherCharges) || 0
const total = duty + vat + other
formData.value.totalCustomsCharges = total.toString()
- return formatNumber(total)
+ return total
})
// Methods
diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowDocuments.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowDocuments.vue
index 5f023c7..b654f55 100644
--- a/webUI/src/components/plugins/import-workflow/ImportWorkflowDocuments.vue
+++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowDocuments.vue
@@ -44,7 +44,7 @@
@@ -183,7 +185,8 @@ const editingDocument = ref(null)
const form = ref()
const valid = ref(false)
const saveLoading = ref(false)
-const selectedFile = ref([])
+const selectedFile = ref(null)
+const fileInputValue = ref([])
const formData = ref({
type: '',
@@ -220,7 +223,7 @@ const documentTypes = [
// Validation rules
const rules = {
required: (value) => !!value || 'این فیلد الزامی است',
- fileRequired: (value) => (value && value.length > 0) || 'انتخاب فایل الزامی است'
+ fileRequired: (value) => !!selectedFile.value || 'انتخاب فایل الزامی است'
}
// Methods
@@ -269,15 +272,15 @@ const saveDocument = async () => {
})
// Add file if selected
- if (selectedFile.value && selectedFile.value.length > 0) {
- formDataToSend.append('file', selectedFile.value[0])
+ if (selectedFile.value) {
+ formDataToSend.append('file', selectedFile.value)
}
const url = editingDocument.value
? `/api/import-workflow/${props.workflowId}/documents/${editingDocument.value.id}/update`
: `/api/import-workflow/${props.workflowId}/documents/create`
- const method = editingDocument.value ? 'PUT' : 'POST'
+ const method = 'POST'
const response = await axios({
method,
@@ -311,15 +314,48 @@ const saveDocument = async () => {
}
}
-const downloadFile = (document) => {
- if (document.filePath) {
- window.open(`/api/import-workflow/documents/${document.id}/download`, '_blank')
+const onFileChange = (val) => {
+ // Normalize input to single File
+ if (Array.isArray(val)) {
+ fileInputValue.value = val
+ selectedFile.value = val.length > 0 ? val[0] : null
+ } else {
+ fileInputValue.value = val ? [val] : []
+ selectedFile.value = val || null
+ }
+}
+
+const downloadFile = async (doc) => {
+ try {
+ const url = `/api/import-workflow/documents/${doc.id}/download`
+ const res = await axios.get(url, { responseType: 'blob' })
+
+ // Try to extract filename from headers
+ const cd = (res.headers && (res.headers['content-disposition'] || res.headers['Content-Disposition'])) || ''
+ let filename = doc.fileName || `document-${doc.id}`
+ const match = /filename\*=UTF-8''([^;]+)|filename="?([^";]+)"?/i.exec(cd)
+ if (match) {
+ filename = decodeURIComponent(match[1] || match[2] || filename)
+ }
+
+ const blob = new Blob([res.data], { type: res.headers['content-type'] || 'application/octet-stream' })
+ const blobUrl = window.URL.createObjectURL(blob)
+ const link = window.document.createElement('a')
+ link.href = blobUrl
+ link.download = filename
+ window.document.body.appendChild(link)
+ link.click()
+ link.remove()
+ window.URL.revokeObjectURL(blobUrl)
+ } catch (e) {
+ Swal.fire('خطا', 'دانلود فایل ناموفق بود', 'error')
}
}
const closeDialog = () => {
editingDocument.value = null
- selectedFile.value = []
+ selectedFile.value = null
+ fileInputValue.value = []
formData.value = {
type: '',
title: '',
diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowItems.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowItems.vue
index f33e97b..9e65d8e 100644
--- a/webUI/src/components/plugins/import-workflow/ImportWorkflowItems.vue
+++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowItems.vue
@@ -22,14 +22,14 @@
no-data-text="آیتمی ثبت نشده است"
>
-
+
{{ formatNumber(item.unitPrice) }}
{{ getCurrency(item) }}
-
+
{{ formatNumber(item.totalPrice) }}
{{ getCurrency(item) }}
@@ -64,23 +64,30 @@
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -232,6 +239,7 @@
import { ref, computed, watch } from 'vue'
import axios from 'axios'
import Swal from 'sweetalert2'
+import Hcommoditysearch from '@/components/forms/Hcommoditysearch.vue'
// Props
const props = defineProps({
@@ -242,6 +250,10 @@ const props = defineProps({
items: {
type: Array,
default: () => []
+ },
+ currency: {
+ type: String,
+ default: 'USD'
}
})
@@ -258,6 +270,16 @@ const valid = ref(false)
const saveLoading = ref(false)
const deleteLoading = ref(false)
+// Commodity selection
+const selectedCommodity = ref(null)
+watch(selectedCommodity, (val) => {
+ if (val) {
+ // Auto-fill name and product code from selected commodity
+ formData.value.name = val.name || ''
+ formData.value.productCode = val.code || ''
+ }
+})
+
const formData = ref({
name: '',
productCode: '',
@@ -322,9 +344,9 @@ const totalPrice = computed(() => {
if (formData.value.quantity && formData.value.unitPrice) {
const total = parseFloat(formData.value.quantity) * parseFloat(formData.value.unitPrice)
formData.value.totalPrice = total.toString()
- return formatNumber(total)
+ return total
}
- return ''
+ return 0
})
// Watch for unit price IRR and quantity changes
@@ -340,6 +362,12 @@ const editItem = (item) => {
editingItem.value = item
formData.value = { ...item }
showAddDialog.value = true
+ // set selected commodity from item if exists
+ if (item && item.commodity) {
+ selectedCommodity.value = item.commodity
+ } else {
+ selectedCommodity.value = null
+ }
}
const deleteItem = (item) => {
@@ -349,6 +377,10 @@ const deleteItem = (item) => {
const saveItem = async () => {
if (!valid.value) return
+ if (!selectedCommodity.value) {
+ Swal.fire({ title: 'هشدار', text: 'انتخاب کالا الزامی است', icon: 'warning' })
+ return
+ }
saveLoading.value = true
try {
@@ -358,10 +390,15 @@ const saveItem = async () => {
const method = editingItem.value ? 'PUT' : 'POST'
+ const payload = {
+ ...formData.value,
+ commodity_id: selectedCommodity.value.id,
+ }
+
const response = await axios({
method,
url,
- data: formData.value
+ data: payload
})
if (response.data.Success) {
@@ -439,16 +476,18 @@ const cancelEdit = () => {
}
}
+// Backward-compat handler for template bindings
+const closeDialog = () => {
+ cancelEdit()
+}
+
// Utilities
const formatNumber = (number) => {
if (!number) return '0'
return new Intl.NumberFormat('fa-IR').format(number)
}
-const getCurrency = (item) => {
- // This should be based on the workflow's currency
- return 'USD'
-}
+const getCurrency = () => props.currency || 'USD'
+
+
+
+
+ ${headers.map(h => `${h} | `).join('')}
+
+ ${sampleData.map(row => `
+
+ ${row.serialNumber} |
+ ${row.commodity_code} |
+ ${row.description} |
+ ${row.warrantyStartDate} |
+ ${row.warrantyEndDate} |
+ ${row.status} |
+
+ `).join('')}
+
+
+