fix(treasury): apply a full receipt or payment to the party's open balance
A settled document of the same amount no longer leaves an existing remaining unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import axios from 'axios';
|
||||
import {
|
||||
Alert as AAlert,
|
||||
@@ -142,6 +142,19 @@ async function createDoc() {
|
||||
error.value = 'برای سایر، مبلغ پرداختشده باید با مبلغ کل یکی باشد.';
|
||||
return;
|
||||
}
|
||||
const partyKey =
|
||||
form.value.partyKind && form.value.partyKind !== 'other' && form.value.partyId
|
||||
? `${form.value.partyKind}:${form.value.partyId}`
|
||||
: '';
|
||||
const openBalance = partyKey
|
||||
? Number(
|
||||
balances.value.find((row) => row.key === partyKey)?.documentRemaining ||
|
||||
balances.value.find((row) => row.key === partyKey)?.remaining ||
|
||||
0,
|
||||
)
|
||||
: 0;
|
||||
const collectsBalance =
|
||||
Boolean(partyKey) && settleAmount === amount && settleAmount > 0 && openBalance > 0;
|
||||
const { data } = await api.post<FinancialDocumentDto>('/treasury/documents', {
|
||||
kind,
|
||||
title: form.value.title,
|
||||
@@ -168,9 +181,11 @@ async function createDoc() {
|
||||
method: 'transfer',
|
||||
notes: '',
|
||||
};
|
||||
ok.value = data.reference
|
||||
? `سند ثبت شد. شماره پیگیری: ${data.reference}`
|
||||
: 'سند ثبت شد.';
|
||||
ok.value = collectsBalance
|
||||
? `${toman(settleAmount)} از ماندهٔ طرف حساب کم شد.`
|
||||
: data.reference
|
||||
? `سند ثبت شد. شماره پیگیری: ${data.reference}`
|
||||
: 'سند ثبت شد.';
|
||||
await load();
|
||||
} catch (e) {
|
||||
error.value = apiMessage(e);
|
||||
@@ -179,6 +194,25 @@ async function createDoc() {
|
||||
}
|
||||
}
|
||||
|
||||
const partyRules = [
|
||||
{
|
||||
validator: async () => {
|
||||
if (!form.value.partyKind) throw new Error('طرف حساب الزامی است');
|
||||
if (form.value.partyKind !== 'other' && !form.value.partyId) {
|
||||
throw new Error('طرف حساب را انتخاب کنید');
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const partyRemainingLabel = computed(() => {
|
||||
const kind = form.value.partyKind;
|
||||
const id = form.value.partyId;
|
||||
if (!kind || kind === 'other' || !id) return '';
|
||||
const row = balances.value.find((item) => item.key === `${kind}:${id}`);
|
||||
return `مانده ${toman(row?.remaining || 0)}`;
|
||||
});
|
||||
|
||||
async function voidDoc(id: string) {
|
||||
if (!window.confirm('این سند و گردش متصل به آن باطل شود؟')) return;
|
||||
try {
|
||||
@@ -210,6 +244,18 @@ onMounted(() => {
|
||||
@finishFailed="onFinishFailed"
|
||||
>
|
||||
<a-row :gutter="[16, 0]">
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="طرف حساب" name="partyKind" :rules="partyRules">
|
||||
<a-row :gutter="8" align="middle">
|
||||
<a-col :span="partyRemainingLabel ? 16 : 24">
|
||||
<TreasuryPartySelect v-model:kind="form.partyKind" v-model:party-id="form.partyId" />
|
||||
</a-col>
|
||||
<a-col v-if="partyRemainingLabel" :span="8">
|
||||
<a-typography-text type="secondary">{{ partyRemainingLabel }}</a-typography-text>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item
|
||||
label="عنوان"
|
||||
@@ -247,11 +293,6 @@ onMounted(() => {
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="طرف حساب" name="partyKind">
|
||||
<TreasuryPartySelect v-model:kind="form.partyKind" v-model:party-id="form.partyId" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="حساب" name="accountId">
|
||||
<a-select show-search option-filter-prop="label"
|
||||
|
||||
@@ -121,6 +121,25 @@ const formTabOptions = [
|
||||
},
|
||||
];
|
||||
|
||||
const partyRules = [
|
||||
{
|
||||
validator: async () => {
|
||||
if (!form.value.partyKind) throw new Error('طرف حساب الزامی است');
|
||||
if (form.value.partyKind !== 'other' && !form.value.partyId) {
|
||||
throw new Error('طرف حساب را انتخاب کنید');
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const partyRemainingLabel = computed(() => {
|
||||
const kind = form.value.partyKind;
|
||||
const id = form.value.partyId;
|
||||
if (!kind || kind === 'other' || !id) return '';
|
||||
const row = balances.value.find((item) => item.key === `${kind}:${id}`);
|
||||
return `مانده ${toman(row?.remaining || 0)}`;
|
||||
});
|
||||
|
||||
const remainingAmount = computed(() => {
|
||||
const total = parseMoneyNumber(String(form.value.amount ?? ''), 0) ?? 0;
|
||||
const settled = parseMoneyNumber(String(form.value.settleAmount ?? ''), 0) ?? 0;
|
||||
@@ -203,6 +222,19 @@ async function createDoc() {
|
||||
error.value = 'برای سایر، مبلغ دریافتشده باید با مبلغ کل یکی باشد.';
|
||||
return;
|
||||
}
|
||||
const partyKey =
|
||||
form.value.partyKind && form.value.partyKind !== 'other' && form.value.partyId
|
||||
? `${form.value.partyKind}:${form.value.partyId}`
|
||||
: '';
|
||||
const openBalance = partyKey
|
||||
? Number(
|
||||
balances.value.find((row) => row.key === partyKey)?.documentRemaining ||
|
||||
balances.value.find((row) => row.key === partyKey)?.remaining ||
|
||||
0,
|
||||
)
|
||||
: 0;
|
||||
const collectsBalance =
|
||||
Boolean(partyKey) && settleAmount === amount && settleAmount > 0 && openBalance > 0;
|
||||
const { data } = await api.post<FinancialDocumentDto>('/treasury/documents', {
|
||||
kind,
|
||||
title: form.value.title,
|
||||
@@ -219,9 +251,11 @@ async function createDoc() {
|
||||
bookedAt: form.value.bookedAt || undefined,
|
||||
});
|
||||
resetForm();
|
||||
ok.value = data.reference
|
||||
? `سند ثبت شد. شماره پیگیری: ${data.reference}`
|
||||
: 'سند ثبت شد.';
|
||||
ok.value = collectsBalance
|
||||
? `${toman(settleAmount)} از ماندهٔ طرف حساب کم شد.`
|
||||
: data.reference
|
||||
? `سند ثبت شد. شماره پیگیری: ${data.reference}`
|
||||
: 'سند ثبت شد.';
|
||||
await load();
|
||||
} catch (e) {
|
||||
error.value = apiMessage(e);
|
||||
@@ -358,6 +392,16 @@ onMounted(() => {
|
||||
<a-card :bordered="false">
|
||||
<a-form ref="mobileFormRef" layout="vertical" :model="form" @finish="createDoc">
|
||||
<div v-show="formTab === 'main'">
|
||||
<a-form-item label="طرف حساب" name="partyKind" :rules="partyRules">
|
||||
<a-row :gutter="8" align="middle">
|
||||
<a-col :span="partyRemainingLabel ? 16 : 24">
|
||||
<TreasuryPartySelect v-model:kind="form.partyKind" v-model:party-id="form.partyId" />
|
||||
</a-col>
|
||||
<a-col v-if="partyRemainingLabel" :span="8">
|
||||
<a-typography-text type="secondary">{{ partyRemainingLabel }}</a-typography-text>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="عنوان درآمد"
|
||||
name="title"
|
||||
@@ -372,12 +416,7 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="[12, 0]">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="طرف حساب" name="partyKind">
|
||||
<TreasuryPartySelect v-model:kind="form.partyKind" v-model:party-id="form.partyId" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-col :span="24">
|
||||
<a-form-item name="method">
|
||||
<template #label>
|
||||
<a-space :size="6">
|
||||
@@ -599,6 +638,18 @@ onMounted(() => {
|
||||
@finishFailed="onFinishFailed"
|
||||
>
|
||||
<a-row :gutter="[16, 0]">
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="طرف حساب" name="partyKind" :rules="partyRules">
|
||||
<a-row :gutter="8" align="middle">
|
||||
<a-col :span="partyRemainingLabel ? 16 : 24">
|
||||
<TreasuryPartySelect v-model:kind="form.partyKind" v-model:party-id="form.partyId" />
|
||||
</a-col>
|
||||
<a-col v-if="partyRemainingLabel" :span="8">
|
||||
<a-typography-text type="secondary">{{ partyRemainingLabel }}</a-typography-text>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item
|
||||
label="عنوان"
|
||||
@@ -636,11 +687,6 @@ onMounted(() => {
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="طرف حساب" name="partyKind">
|
||||
<TreasuryPartySelect v-model:kind="form.partyKind" v-model:party-id="form.partyId" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="حساب" name="accountId">
|
||||
<a-select show-search option-filter-prop="label"
|
||||
|
||||
Reference in New Issue
Block a user