diff --git a/apps/api/src/integrations/tahesab/documents.service.ts b/apps/api/src/integrations/tahesab/documents.service.ts
index cb1be53..f721a34 100644
--- a/apps/api/src/integrations/tahesab/documents.service.ts
+++ b/apps/api/src/integrations/tahesab/documents.service.ts
@@ -16,8 +16,17 @@ function asAsnadList(raw: unknown): Array> {
if (!raw) return [];
if (Array.isArray(raw)) return raw as Array>;
if (typeof raw === 'object') {
- return Object.values(raw as Record).filter(
- (v) => v && typeof v === 'object',
+ const obj = raw as Record;
+ for (const key of ['DoListAsnad', 'Asnad', 'asnad', 'Items', 'items', 'Data']) {
+ const nested = obj[key];
+ if (Array.isArray(nested)) {
+ return nested.filter((v) => v && typeof v === 'object') as Array<
+ Record
+ >;
+ }
+ }
+ return Object.values(obj).filter(
+ (v) => v && typeof v === 'object' && !Array.isArray(v),
) as Array>;
}
return [];
@@ -68,8 +77,8 @@ export class TahesabDocumentsService {
);
const link = await this.requireLink(organizationId, personId, resolvedId);
const { api } = await this.connections.getApi(organizationId, resolvedId);
- // Count_Last = -1 برای مانده ردیفبهردیف مثل همکار
- const raw = await api.doListAsnad(-1, link.moshtariCode, from, to);
+ // Count_Last = سقف تعداد سند برگشتی (۰ در نمونه گاهی خالی برمیگرداند)
+ const raw = await api.doListAsnad(500, link.moshtariCode, from, to);
const items = asAsnadList(raw);
return {
connectionId: resolvedId,
diff --git a/apps/api/src/integrations/tahesab/tahesab-methods.ts b/apps/api/src/integrations/tahesab/tahesab-methods.ts
index 5562019..232d61b 100644
--- a/apps/api/src/integrations/tahesab/tahesab-methods.ts
+++ b/apps/api/src/integrations/tahesab/tahesab-methods.ts
@@ -222,11 +222,14 @@ export class TahesabApi {
fromShamsi: string,
toShamsi: string,
) {
+ // OpenAPI: Count_Last, Moshtari_Code, AzTarikhShamsi, TaTarikhShamsi, FilterNoSanad, Mande_Jens_Felez
return this.call('DoListAsnad', 'DoListAsnad', [
countLast,
moshtariCode,
fromShamsi,
toShamsi,
+ '',
+ 0,
]);
}
diff --git a/apps/web/src/components/person-assets/PersonAssetsPanel.vue b/apps/web/src/components/person-assets/PersonAssetsPanel.vue
index 8efc08c..959c5ac 100644
--- a/apps/web/src/components/person-assets/PersonAssetsPanel.vue
+++ b/apps/web/src/components/person-assets/PersonAssetsPanel.vue
@@ -3,7 +3,13 @@ import { computed, onMounted, ref, watch } from 'vue';
import axios from 'axios';
import { api } from '@/lib/api';
import { formatMoney } from '@/lib/money';
+import {
+ dateToJalali,
+ formatLocalDateInput,
+ parseLocalInput,
+} from '@/lib/jalali';
import MoneyInput from '@/components/MoneyInput.vue';
+import JalaliDateInput from '@/components/JalaliDateInput.vue';
import type {
PersonAccountingLinkDto,
PersonAssetsDto,
@@ -16,6 +22,10 @@ const props = defineProps<{
personId: string;
}>();
+const emit = defineEmits<{
+ linkChanged: [moshtariCode: number | null];
+}>();
+
const loading = ref(false);
const error = ref('');
const ok = ref('');
@@ -26,6 +36,7 @@ const assets = ref(null);
const activeTab = ref<'مانده حساب' | 'جزئیات حساب' | 'ثبت سند'>('مانده حساب');
const asnadLoading = ref(false);
const asnadItems = ref[]>([]);
+/** مدل JalaliDateInput = تاریخ محلی میلادی YYYY-MM-DD */
const fromDate = ref('');
const toDate = ref('');
const manualCode = ref('');
@@ -120,18 +131,28 @@ function formatMandehAmount(amount: string | number, unit: string) {
return abs.toLocaleString('fa-IR', { maximumFractionDigits: 3 });
}
+/** تبدیل تاریخ محلی میلادی به شمسی YYYY-MM-DD برای API تهحساب */
+function toShamsiYmd(localIso: string): string | null {
+ const d = parseLocalInput(localIso);
+ if (!d) return null;
+ const { jy, jm, jd } = dateToJalali(d);
+ return `${jy}-${String(jm).padStart(2, '0')}-${String(jd).padStart(2, '0')}`;
+}
+
function defaultJalaliRange() {
- // تقریبی: کاربر میتواند عوض کند؛ پیشفرض بازه یکماهه متنی
const now = new Date();
- // بدون وابستگی سنگین: مقادیر نمونه قابل ویرایش
- toDate.value = `${now.getFullYear() - 621}-01-01`;
- // بهتر: از API تاریخ نخواهیم؛ فیلدها را خالیتر با placeholder بگذاریم
- const y = 1405;
- fromDate.value = `${y}-01-01`;
- toDate.value = `${y}-12-29`;
- sanad.value.year = y;
- sanad.value.month = 1;
- sanad.value.day = 1;
+ const from = new Date(now);
+ from.setMonth(from.getMonth() - 6);
+ fromDate.value = formatLocalDateInput(from);
+ toDate.value = formatLocalDateInput(now);
+ const j = dateToJalali(now);
+ sanad.value.year = j.jy;
+ sanad.value.month = j.jm;
+ sanad.value.day = j.jd;
+}
+
+function emitLinkCode() {
+ emit('linkChanged', currentLink.value?.moshtariCode ?? null);
}
async function loadConnectionsAndLinks() {
@@ -155,6 +176,12 @@ async function loadConnectionsAndLinks() {
) {
connectionId.value = def?.id ?? '';
}
+ if (!currentLink.value && links.value.length) {
+ const preferred =
+ links.value.find((l) => l.isDefaultConnection) ?? links.value[0];
+ if (preferred) connectionId.value = preferred.connectionId;
+ }
+ emitLinkCode();
} catch (e) {
error.value = axios.isAxiosError(e)
? String(
@@ -162,6 +189,7 @@ async function loadConnectionsAndLinks() {
'بارگذاری اتصال تهحساب ناموفق بود.',
)
: 'بارگذاری اتصال تهحساب ناموفق بود.';
+ emit('linkChanged', null);
} finally {
loading.value = false;
}
@@ -195,8 +223,10 @@ async function refreshAssets() {
async function loadAsnad() {
if (!connectionId.value || !currentLink.value) return;
- if (!fromDate.value || !toDate.value) {
- error.value = 'تاریخ از و تا را وارد کنید (شمسی YYYY-MM-DD).';
+ const from = toShamsiYmd(fromDate.value);
+ const to = toShamsiYmd(toDate.value);
+ if (!from || !to) {
+ error.value = 'تاریخ از و تا را از تقویم انتخاب کنید.';
return;
}
asnadLoading.value = true;
@@ -207,12 +237,16 @@ async function loadAsnad() {
{
params: {
connectionId: connectionId.value,
- from: fromDate.value,
- to: toDate.value,
+ from,
+ to,
},
+ timeout: 60_000,
},
);
asnadItems.value = data.items ?? [];
+ ok.value = asnadItems.value.length
+ ? `${asnadItems.value.length} سند نمایش داده شد.`
+ : 'در این بازه سندی یافت نشد.';
} catch (e) {
error.value = axios.isAxiosError(e)
? String(
@@ -315,6 +349,7 @@ async function unlink() {
`/integrations/tahesab/people/${props.personId}/links/${connectionId.value}`,
);
assets.value = null;
+ asnadItems.value = [];
await loadConnectionsAndLinks();
}
@@ -355,10 +390,17 @@ async function pushSanad() {
watch(connectionId, async () => {
matchCandidates.value = [];
asnadItems.value = [];
+ emitLinkCode();
if (currentLink.value) await refreshAssets();
else assets.value = null;
});
+watch(activeTab, (t) => {
+ if (t === 'جزئیات حساب' && currentLink.value && !asnadItems.value.length) {
+ void loadAsnad();
+ }
+});
+
onMounted(async () => {
defaultJalaliRange();
await loadConnectionsAndLinks();
@@ -374,8 +416,8 @@ onMounted(async () => {
-