From 133fb124b74eee683ad2fcd889dd1c1cbcf1ad8b Mon Sep 17 00:00:00 2001 From: Kavehhn174 Date: Sun, 16 Aug 2026 14:53:46 +0330 Subject: [PATCH] Fix payment transaction edit save and Jalali due date display. Convert dates between Jalali picker values and ISO before API calls, and format due dates with proper Persian calendar tokens and digits. --- src/composables/usePersianDate.js | 31 ++++++++++++++++++------ src/views/payments/PaymentDetailView.vue | 22 +++++++++++------ src/views/payments/PaymentListView.vue | 5 +++- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/composables/usePersianDate.js b/src/composables/usePersianDate.js index de1cc4a..a4c890e 100644 --- a/src/composables/usePersianDate.js +++ b/src/composables/usePersianDate.js @@ -19,34 +19,49 @@ export function usePersianDate() { return result; }; - const formatJalali = (date, formatStr = 'YYYY/MM/DD') => { + const formatJalali = (date, formatStr = 'jYYYY/jMM/jDD') => { if (!date) return '-'; try { - return moment(date).locale('fa').format(formatStr); + return toPersianDigits(moment(date).locale('fa').format(formatStr)); } catch (e) { return '-'; } }; const formatJalaliWithTime = (date) => { - return formatJalali(date, 'YYYY/MM/DD - HH:mm'); + return formatJalali(date, 'jYYYY/jMM/jDD - HH:mm'); }; - const jalaliToIso = (jalaliStr) => { - if (!jalaliStr) return null; + const toJalaliPickerValue = (value) => { + if (!value) return ''; try { - const latinStr = toLatinDigits(jalaliStr); - return moment(latinStr, 'jYYYY/jMM/jDD').toISOString(); + return moment(value).locale('fa').format('jYYYY/jMM/jDD'); } catch (e) { - return null; + return ''; } }; + const toGregorianIso = (jalaliValue) => { + if (!jalaliValue) return undefined; + if (jalaliValue instanceof Date) return jalaliValue.toISOString(); + try { + const latin = toLatinDigits(String(jalaliValue)); + const m = moment(latin, 'jYYYY/jMM/jDD'); + return m.isValid() ? m.toDate().toISOString() : undefined; + } catch (e) { + return undefined; + } + }; + + const jalaliToIso = (jalaliStr) => toGregorianIso(jalaliStr) || null; + return { toPersianDigits, toLatinDigits, formatJalali, formatJalaliWithTime, + toJalaliPickerValue, + toGregorianIso, jalaliToIso }; } diff --git a/src/views/payments/PaymentDetailView.vue b/src/views/payments/PaymentDetailView.vue index fa84cd9..afe67d2 100644 --- a/src/views/payments/PaymentDetailView.vue +++ b/src/views/payments/PaymentDetailView.vue @@ -235,7 +235,7 @@ import DatePicker from 'vue3-persian-datetime-picker'; const route = useRoute(); const paymentId = route.params.id; -const { toPersianDigits, formatJalali } = usePersianDate(); +const { toPersianDigits, formatJalali, toJalaliPickerValue, toGregorianIso } = usePersianDate(); const { showSuccess, showError } = useToast(); const payment = ref(null); @@ -293,6 +293,8 @@ const fetchPayment = async () => { const handleRecordTransaction = async () => { if (!trxForm.amount) { showError('لطفا مبلغ را وارد کنید'); return; } if (!trxForm.dueDate) { showError('لطفا تاریخ سررسید را وارد کنید'); return; } + const dueDate = toGregorianIso(trxForm.dueDate); + if (!dueDate) { showError('تاریخ سررسید نامعتبر است'); return; } if (trxForm.status === 'paid' && !trxForm.receiptNumber) { showError('لطفا شماره فیش یا پیگیری را وارد کنید'); return; @@ -303,13 +305,14 @@ const handleRecordTransaction = async () => { const payload = { amount: trxForm.amount, status: trxForm.status, - dueDate: trxForm.dueDate, + dueDate, notes: trxForm.notes || undefined }; if (trxForm.status === 'paid') { payload.method = trxForm.method; payload.receiptNumber = trxForm.receiptNumber; - if (trxForm.date) payload.date = trxForm.date; + const paymentDate = toGregorianIso(trxForm.date); + if (paymentDate) payload.date = paymentDate; } const res = await paymentApi.recordTransaction(paymentId, payload); @@ -330,8 +333,8 @@ const openEditTransaction = (trx) => { editForm.status = trx.status || (trx.date ? 'paid' : 'pending'); editForm.method = trx.method || 'card'; editForm.receiptNumber = trx.receiptNumber || ''; - editForm.dueDate = trx.dueDate || ''; - editForm.date = trx.date || ''; + editForm.dueDate = toJalaliPickerValue(trx.dueDate); + editForm.date = toJalaliPickerValue(trx.date); editForm.notes = trx.notes || ''; showEditModal.value = true; }; @@ -345,19 +348,24 @@ const handleUpdateTransaction = async () => { showError('لطفا تاریخ سررسید را وارد کنید'); return; } + const dueDate = toGregorianIso(editForm.dueDate); + if (!dueDate) { + showError('تاریخ سررسید نامعتبر است'); + return; + } isSubmittingEdit.value = true; try { const payload = { amount: editForm.amount, status: editForm.status, - dueDate: editForm.dueDate, + dueDate, notes: editForm.notes }; if (editForm.status === 'paid') { payload.method = editForm.method; payload.receiptNumber = editForm.receiptNumber; - payload.date = editForm.date || undefined; + payload.date = toGregorianIso(editForm.date); } const res = await paymentApi.updateTransaction(editingTransactionId.value, payload); diff --git a/src/views/payments/PaymentListView.vue b/src/views/payments/PaymentListView.vue index dac5efe..f6f8804 100644 --- a/src/views/payments/PaymentListView.vue +++ b/src/views/payments/PaymentListView.vue @@ -198,7 +198,7 @@ import Checkbox from 'primevue/checkbox'; import Textarea from 'primevue/textarea'; import DatePicker from 'vue3-persian-datetime-picker'; -const { toPersianDigits, formatJalali } = usePersianDate(); +const { toPersianDigits, formatJalali, toGregorianIso } = usePersianDate(); const { showSuccess, showError } = useToast(); const { @@ -326,6 +326,8 @@ const handleCreatePayment = async () => { if (!createForm.user) { showError('لطفا کاربر را انتخاب کنید'); return; } if (!createForm.amount) { showError('لطفا مبلغ را وارد کنید'); return; } if (!createForm.dueDate) { showError('لطفا تاریخ سررسید را وارد کنید'); return; } + const dueDate = toGregorianIso(createForm.dueDate); + if (!dueDate) { showError('تاریخ سررسید نامعتبر است'); return; } if (hasDiscount.value && (createForm.discount || 0) > createForm.amount) { showError('مبلغ تخفیف نمی‌تواند بیشتر از مبلغ کل باشد'); @@ -336,6 +338,7 @@ const handleCreatePayment = async () => { try { await paymentApi.create({ ...createForm, + dueDate, discount: hasDiscount.value ? (createForm.discount || 0) : 0, notify: { ...createNotify } });