Submit multi-company cart as one unified order and invoice.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-15 08:52:50 +02:00
co-authored by Cursor
parent 1b4a149e76
commit bc35c4f887
7 changed files with 57 additions and 60 deletions
+2 -10
View File
@@ -46,17 +46,9 @@ export function useCartPage() {
submitError.value = 'سبد خرید خالی است یا با سرور همگام نشد.'
return
}
const created = await orderStore.submitOrder(cartStore.activeCart)
const order = await orderStore.submitOrder(cartStore.activeCart)
await cartStore.hydrate()
if (created.length === 1) {
router.replace(`/orders/${created[0]!.id}/success`)
return
}
// چند شرکت → چند سفارش؛ به لیست سفارش‌ها برو
router.replace({
path: '/orders',
query: { submitted: String(created.length) },
})
router.replace(`/orders/${order.id}/success`)
} catch (e) {
submitError.value = e instanceof Error ? e.message : 'ثبت سفارش ناموفق بود.'
await cartStore.hydrate()
+38 -35
View File
@@ -117,9 +117,9 @@ export const useOrderStore = defineStore('order', () => {
/**
* سفارش بدون روش تسویه ثبت می‌شود؛ مشتری بعد از قیمت‌گذاری مدیریت
* روش تسویه را انتخاب می‌کند.
* سبد چندشرکتی: برای هر شرکت یک سفارش جدا ساخته می‌شود.
* اقلام همه شرکت‌ها در یک فاکتور واحد ثبت می‌شوند.
*/
async function submitOrder(cart: Cart): Promise<Order[]> {
async function submitOrder(cart: Cart): Promise<Order> {
if (!cart.items.length) {
throw new Error('سبد خرید خالی است.')
}
@@ -134,43 +134,25 @@ export const useOrderStore = defineStore('order', () => {
throw new Error('شرکت سبد مشخص نیست. سبد را خالی کنید و دوباره اضافه کنید.')
}
const createdOrders: Order[] = []
try {
for (const companyId of companyIds) {
const itemsForOrder = cart.items.filter((item) => item.companyId === companyId)
if (!itemsForOrder.length) continue
const order = await apiRequest<Order>('/orders', {
method: 'POST',
body: {
companyId,
notes: cart.notes,
items: itemsForOrder.map((item) => ({
productId: item.productId,
meterage: Number(item.meterage),
notes: item.notes,
})),
},
})
orders.value.unshift(order)
createdOrders.push(order)
}
const order = await apiRequest<Order>('/orders', {
method: 'POST',
body: {
companyId: companyIds[0],
notes: cart.notes,
items: cart.items.map((item) => ({
productId: item.productId,
meterage: Number(item.meterage),
notes: item.notes,
})),
},
})
orders.value.unshift(order)
clearCheckDraft()
return order
} catch (e) {
if (createdOrders.length) {
// بخشی ثبت شده؛ سفارش‌های موفق را نگه می‌داریم و خطا را با توضیح برمی‌گردانیم
clearCheckDraft()
const names = createdOrders.map((o) => o.orderNumber).join('، ')
throw new Error(
e instanceof ApiError
? `${e.message} (سفارش‌های ثبت‌شده: ${names})`
: `ثبت بخشی از سفارش‌ها ناموفق بود. ثبت‌شده: ${names}`,
)
}
throw new Error(e instanceof ApiError ? e.message : 'ثبت سفارش ناموفق بود.')
}
clearCheckDraft()
return createdOrders
}
/** انتخاب روش تسویه پس از صدور فاکتور. */
@@ -256,6 +238,26 @@ export const useOrderStore = defineStore('order', () => {
}
}
async function getBankAccountsForOrder(order: Order) {
const companyIds = [
...new Set(
[
order.companyId,
...order.items.map((item) => item.companyId).filter(Boolean),
].filter(Boolean) as string[],
),
]
const catalog = useCatalogStore()
const lists = await Promise.all(companyIds.map((id) => catalog.loadBankAccounts(id)))
const byId = new Map<string, (typeof lists)[number][number]>()
for (const list of lists) {
for (const account of list) {
byId.set(account.id, account)
}
}
return [...byId.values()]
}
async function getBankAccountsForCompany(companyId: string) {
return useCatalogStore().loadBankAccounts(companyId)
}
@@ -284,6 +286,7 @@ export const useOrderStore = defineStore('order', () => {
hydrate,
resetLocal,
fetchOrder,
getBankAccountsForOrder,
getBankAccountsForCompany,
}
})
+2
View File
@@ -154,6 +154,8 @@ export interface OrderItem {
discount?: number
lineTotal?: number
notes?: string
companyId?: string
companyName?: string
}
export interface OrderStatusHistoryEntry {
@@ -194,7 +194,7 @@ const quickLinks = [
{{ submitting ? 'در حال ثبت…' : 'ثبت پیش‌سفارش' }}
</button>
<p class="cart-summary-card__note">
اقلام همه شرکت‌ها در یک سبد هستند؛ با ثبت، برای هر شرکت یک پیش‌سفارش جدا ساخته می‌شود.
اقلام همه شرکت‌ها در یک سبد و یک فاکتور ثبت می‌شوند؛ پس از قیمت‌گذاری، یک‌بار تسویه می‌کنید.
</p>
</div>
+1 -1
View File
@@ -100,7 +100,7 @@ const emit = defineEmits<{
</div>
</div>
<p class="cart-mobile-page__hint">
پس از ثبت، برای هر شرکت یک پیش‌سفارش جداگانه ساخته می‌شود و مدیریت قیمت‌گذاری می‌کند.
پس از ثبت، همه اقلام در یک پیش‌سفارش واحد قرار می‌گیرند و مدیریت قیمت‌گذاری می‌کند.
</p>
<BaseButton block :loading="submitting" @click="emit('checkout')">ثبت پیش‌سفارش</BaseButton>
</div>
+8 -8
View File
@@ -16,7 +16,6 @@ const catalogStore = useCatalogStore()
const bankAccounts = ref<BankAccount[]>([])
const { orderId, order } = useRequirePricedOrder()
const companyId = computed(() => order.value?.companyId ?? '')
const companyName = computed(() => order.value?.companyName ?? '')
watch(
@@ -28,14 +27,14 @@ watch(
)
watch(
companyId,
() => order.value?.id,
async (id) => {
if (!id) {
if (!id || !order.value) {
bankAccounts.value = []
return
}
if (!catalogStore.getCompany(id)) await catalogStore.loadCompanies()
bankAccounts.value = await catalogStore.loadBankAccounts(id)
if (!catalogStore.companies.length) await catalogStore.loadCompanies()
bankAccounts.value = await orderStore.getBankAccountsForOrder(order.value)
},
{ immediate: true },
)
@@ -51,9 +50,10 @@ const expiryMessage = computed(() => {
})
const accountsSectionTitle = computed(() => {
const company = catalogStore.getCompany(companyId.value)
const name = (company?.name || companyName.value).replace(/^شرکت\s+/u, '')
return `شماره حساب‌های شرکت ${name}`
const name = companyName.value.replace(/^شرکت\s+/u, '')
return name
? `شماره حساب‌های واریز — ${name}`
: 'شماره حساب‌های واریز'
})
function formatCardNumber(value: string) {
+5 -5
View File
@@ -103,18 +103,18 @@ watch(destinationAccountId, () => {
})
const bankAccounts = ref(
[] as Awaited<ReturnType<typeof orderStore.getBankAccountsForCompany>>,
[] as Awaited<ReturnType<typeof orderStore.getBankAccountsForOrder>>,
)
watch(
() => order.value?.companyId,
async (companyId) => {
if (!companyId) {
() => order.value?.id,
async (id) => {
if (!id || !order.value) {
bankAccounts.value = []
return
}
try {
bankAccounts.value = await orderStore.getBankAccountsForCompany(companyId)
bankAccounts.value = await orderStore.getBankAccountsForOrder(order.value)
} catch {
bankAccounts.value = []
}