Fix checkout order submit payload and cash settlement UX.

Drop non-whitelisted fields that caused 400 on POST /orders, prevent double submit on checks, and only show cash success after create succeeds.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-08 14:55:34 +03:30
co-authored by Cursor
parent 72cc6000f1
commit b788fe069e
3 changed files with 64 additions and 15 deletions
+39 -9
View File
@@ -115,21 +115,36 @@ export const useOrderStore = defineStore('order', () => {
throw new Error('سبد خرید با سرور همگام نیست. لطفاً دوباره محصولات را به سبد اضافه کنید.')
}
const companyItems = cart.items.filter((item) => item.companyId === companyId)
const itemsForOrder = companyItems.length ? companyItems : cart.items
const body = {
companyId,
settlementType,
settlementMethod: settlementType,
checkMode: settlementType === 'check' ? (checkMode ?? 'full') : undefined,
notes: cart.notes,
items: cart.items.map((item) => ({
items: itemsForOrder.map((item) => ({
productId: item.productId,
meterage: item.meterage,
requestedMeterage: item.meterage,
notes: item.notes,
})),
checks:
settlementType === 'check' && checks
? checks.map(({ id: _id, ...rest }) => rest)
? checks.map((c) => ({
amount: c.amount,
dueDate: c.dueDate,
sayadId: c.sayadId,
checkNumber: c.checkNumber,
ownerNationalId: c.ownerNationalId,
ownerFirstName: c.ownerFirstName,
ownerLastName: c.ownerLastName,
bankName: c.bankName,
branchName: c.branchName,
frontImage: c.frontImage,
backImage: c.backImage,
notes: c.notes,
mode: c.mode,
}))
: undefined,
}
@@ -154,7 +169,7 @@ export const useOrderStore = defineStore('order', () => {
receipt: Omit<CashPaymentReceipt, 'id' | 'submittedAt'>,
) {
try {
const order = await apiRequest<Order>(`/orders/${orderId}/cash-receipt`, {
await apiRequest(`/orders/${orderId}/cash-receipt`, {
method: 'POST',
body: {
amount: receipt.amount,
@@ -166,9 +181,10 @@ export const useOrderStore = defineStore('order', () => {
notes: receipt.notes,
},
})
const idx = orders.value.findIndex((o) => o.id === orderId)
if (idx >= 0) orders.value[idx] = order
else orders.value.unshift(order)
const order = await fetchOrder(orderId)
if (!order) {
throw new Error('رسید ثبت شد ولی دریافت سفارش ناموفق بود.')
}
return order
} catch (e) {
throw new Error(e instanceof ApiError ? e.message : 'ثبت رسید ناموفق بود.')
@@ -180,7 +196,21 @@ export const useOrderStore = defineStore('order', () => {
const order = await apiRequest<Order>(`/orders/${orderId}/checks`, {
method: 'PATCH',
body: {
checks: checks.map(({ id: _id, ...rest }) => rest),
checks: checks.map((c) => ({
amount: c.amount,
dueDate: c.dueDate,
sayadId: c.sayadId,
checkNumber: c.checkNumber,
ownerNationalId: c.ownerNationalId,
ownerFirstName: c.ownerFirstName,
ownerLastName: c.ownerLastName,
bankName: c.bankName,
branchName: c.branchName,
frontImage: c.frontImage,
backImage: c.backImage,
notes: c.notes,
mode: c.mode,
})),
},
})
const idx = orders.value.findIndex((o) => o.id === orderId)
+8 -4
View File
@@ -105,8 +105,8 @@ async function registerReceipt() {
<div class="cash-page__scroll page__scroll">
<FormErrorBanner :message="formError" />
<div class="cash-page__success">
<IconSuccessCircle :size="56" />
<div class="cash-page__success" :class="{ 'cash-page__success--done': createdOrder }">
<IconSuccessCircle v-if="createdOrder" :size="56" />
<p class="cash-page__success-title">
{{ createdOrder ? 'فاکتور شما ثبت شد.' : 'آماده ثبت فاکتور نقدی' }}
</p>
@@ -154,8 +154,8 @@ async function registerReceipt() {
<p class="desktop-page__subtitle">{{ expiryMessage }}</p>
</header>
<div class="cash-page__success">
<IconSuccessCircle :size="56" />
<div class="cash-page__success" :class="{ 'cash-page__success--done': createdOrder }">
<IconSuccessCircle v-if="createdOrder" :size="56" />
<p class="cash-page__success-title">
{{ createdOrder ? 'فاکتور شما ثبت شد.' : 'آماده ثبت فاکتور نقدی' }}
</p>
@@ -228,6 +228,10 @@ async function registerReceipt() {
margin: 0;
font-size: 1rem;
font-weight: 700;
color: var(--color-text);
}
.cash-page__success--done .cash-page__success-title {
color: var(--color-success);
}
+17 -2
View File
@@ -19,6 +19,7 @@ const cartStore = useCartStore()
const orderStore = useOrderStore()
const authStore = useAuthStore()
const formError = ref('')
const submitting = ref(false)
const isCheckout = computed(() => route.name === 'check-list')
@@ -90,7 +91,9 @@ function toggleMenu(id: string) {
async function submitOrder() {
if (!authStore.user || !cartStore.activeCart || checks.value.length === 0) return
if (submitting.value) return
formError.value = ''
submitting.value = true
try {
const order = await orderStore.submitOrder(
@@ -104,6 +107,8 @@ async function submitOrder() {
router.replace(`/orders/${order.id}/success`)
} catch (e) {
formError.value = e instanceof Error ? e.message : 'ثبت سفارش ناموفق بود.'
} finally {
submitting.value = false
}
}
</script>
@@ -194,7 +199,12 @@ async function submitOrder() {
</div>
<div v-if="isCheckout && orderStore.draftChecks.length > 0" class="check-list-page__footer">
<BaseButton block :disabled="checks.length === 0" @click="submitOrder">
<BaseButton
block
:disabled="checks.length === 0"
:loading="submitting"
@click="submitOrder"
>
ارسال برای بررسی
</BaseButton>
</div>
@@ -269,7 +279,12 @@ async function submitOrder() {
<strong>{{ toPersianDigits(String(rass.rassDays)) }} روز</strong>
</div>
<div v-if="isCheckout && orderStore.draftChecks.length > 0" class="desktop-summary-panel__action">
<BaseButton block :disabled="checks.length === 0" @click="submitOrder">
<BaseButton
block
:disabled="checks.length === 0"
:loading="submitting"
@click="submitOrder"
>
ارسال برای بررسی
</BaseButton>
</div>