راهنمای پنل ادمین «حسابیار طلا و جواهر»
این راهنما برای صاحب مغازه و حسابدار نوشته شده — با زبان ساده و مثال. هدف این است که بدون دانش فنی بتوانی با پنل کار کنی و بفهمی هر عدد از کجا میآید. بخش فنیِ مخصوص توسعهدهنده در انتهای سند و جدا مشخص شده است.
سامانه یک پنل تکصفحهای فارسی (راستبهچپ) است. دادهها روی سرور ذخیره و بین همهٔ کاربران مشترکاند. نرخ لحظهای (مظنه، گرم ۱۸، دلار، انس) بالای صفحه از منبع خودکار نمایش داده میشود.
#فهرست
- نگاه کلی: صفحهها کجا هستند
- مفهوم مانده: بدهکار و بستانکار
- سند چیست و چطور ثبت میشود
- ستون «تشخیص»: قلب مدل کیمیا
- ستون «شرح» و «بابت»
- وزن ۷۵۰ و عیار
- مالیات سند فروش (فرمول جدید)
- حساب بانکی و کارتخوان (پوز)
- حوالهٔ دوطرفه: ریالی و طلا
- نوع حسابها، امانات، سرمایه و برداشت
- مخارج مغازه و حساب داخلی
- گزارشها و سود و زیان
- اتاق فرمان و دسترسیها
- تنظیمات
- عیار تهحساب: تسویهٔ طلا با عیار توافقی
- گروههای دسترسی اشخاص و هشدار عملیات
- عکس اجناس
- دفتر ذوب و آبشده
- پیوست سند
- پیشنویس تکفروشی
- نسخهٔ پشتیبان
- وام و تسهیلات بانکی
- چند صفحه همزمان: میزِ کارِ ساعتِ شلوغی
- تبدیل متفرقه به ویترین و «عیار شخصی»
- ریز ورود و خروج و جمع ردیفهای انتخابی
- سند چاپی: فاکتور و قبض
- گردش موجودی: کاردکس هر قلم
- دفتر چک: چک شخصی و دریافتی
- خلاصه وضعیت: چک، زیان و سربهسر
- کالای غیرطلایی: جنسی که قیمت طلا رویش اثر ندارد
- اصلاح موجودی: وقتی دفتر با ترازو نمیخواند
- تعمیرات و آبکاری: جنسی که فروخته نشده، فقط بیرون رفته
- پوشش ریسک: بستن مظنه و وضعیت باز
- تراز خرید و فروش و نوار پایین صفحه
- مرجوعی در تکفروشی: وقتی مشتری جنس را پس میآورد
- سکهٔ پارسیان: اجرت عددی و معافیت ارزش افزوده
- فروش قسطی: قسط ریالی و قسط طلایی
- دریافت قسط: وقتی مشتری پولِ قسط را میآورد
- انتقال سند: ابزار قیچی
- جستجوی هوشمند: شخص، جنس و سند
- سنگ و نگین: انگشتر یاقوت، عقیق و فیروزه
- دفتر روزانه: کارِ امروز، ردیفبهردیف
- تاریخچه کارها: چه کسی، کِی، چه چیزی را عوض کرد
- اجاره طلا: طلای سرمایهگذار نزد شما
- کارکرد ارز و سکه (سایت فروشگاه)
- کار جور: سی قلم خردهریز در یک ردیف
- آبشدهٔ شرطی: طلایی که هنوز عیارش را نمیدانی
- مرجوعی نزدِ سازنده و بنکدار: دفترِ فی و خرید خالص
- فیِ فروش نقدی، فیِ نسیه و تخفیفِ خوشحساب
- دفتر معین: گردشِ یک طرف حساب، ردیفبهردیف
- معکوسِ سند: خرید و فروشِ آینه با Ctrl+H
- ماشین حسابِ سلول: جمعِ چند وزن با کلید =
- شمارهٔ دوم و تصفیه با متفرقه
- مرجوعیِ شناسنامهدار: همان آبشده و همان چک، نه یکی شبیهِ آن
- برداشت شخصی به نامِ صاحبش: سهم شرکا از هر سه در
- تسویه با آبشده: با لُنگهٔ واقعیِ انبار، نه یک متفرقهٔ ساختگی
- سندِ عقبتاریخ (جامونده): وقتی شمارهٔ سند و تاریخش همسو نیستند
- مسیر کنترل و بستن روز: از ماندهها تا سود واقعی
- متفرقه با وزن ترازو: تفکیک عیار و معادل خودکار ۷۵۰
- ماندهٔ سنگ و نگین: انبارِ نگین که روی لیبل بسته میشود
- مشتریان تک: یک حساب، صد مشتری
- موجودی متفرقه در خلاصه وضعیت: به تفکیک عیار، از دلِ اسناد
- آب کردن طلا: برداشتِ متفرقه از موجودی، درونِ قبضِ ذوب
- سندِ تکفروشی: برای هر مشتریِ گذری یک حساب نساز
- هشدار گروهها: هر گروه چه چیزی را میگیرد و چه چیزی را میدهد
- بخش فنی (توسعهدهنده)
- بهروزرسانی نسخهٔ شبکه: قفل اصلی و ترتیب نصب
- کسر و اضافه: اصلاح حساب بدون جابهجایی فیزیکی
- اولین مرجوعی یک جنس: ثبت مبنای فی بدون تغییر موجودی
دامنهٔ این راهنما: بخشهای ۱ تا ۴۴ و ۴۶ تا ۵۴ دربارهٔ پنل ادمین (/admin) است. بخش ۴۵ مربوط به سایت فروشگاه (/) است که برنامهای جداگانه با دادهٔ خودش است.
#۱. نگاه کلی: صفحهها کجا هستند
منوی کناری (سایدبار) این بخشها را دارد:
| بخش | کاربرد |
|---|---|
| داشبورد | نمای کلی: شاخصها، طلب و بدهی، اسناد اخیر |
| دستیار هوشمند | چت حسابدار خودکار و تحلیلگر |
| اشخاص و حسابها | مشتری، همکار، کارگاه؛ دفتر حساب هر شخص |
| کالا و انبار | موجودی کالا، کاتالوگ اجناس و «تبدیل متفرقه به ویترین» |
| گردش موجودی | کاردکسِ ورود و خروجِ هر قلم و پیداکردنِ سندِ جاافتاده یا تکراری |
| تعمیرات و آبکاری | جنسی که نزد تعمیرکار است، بازگشتش و اجرتی که باید بدهی |
| پوشش ریسک | چند گرم طلا «باز» مانده، ریسک نوسان، و بستنِ مظنه با بنکدار |
| ذوب و آبشده | قبضهای ذوب: ارسال متفرقه به ریگیری و ثبت آبشدهٔ برگشتی |
| حساب بانکی | حسابهای بانکی + کارتخوان (پوز) و تسویه |
| دفتر چک | چکهای صادره و دریافتی، سررسید، راسگیری و پاس کردن |
| وام و تسهیلات | وامهای بانکی، سود و کارمزد، و پرداخت اقساط |
| اجاره طلا | طلای سرمایهگذار که نزد شماست: اصلِ ثابت و اجارهٔ ماهانه |
| هزینهها | مخارج مغازه و حساب داخلی (خروج/ورود، بابت، برداشت شخصی) |
| نوع حسابها | گروههای حساب، امانات، سرمایه و برداشت |
| خلاصه وضعیت | وضعیت کلی طلب، بدهی و موجودی |
| دفتر روزانه | کارِ روزانه ردیفبهردیف: بازه، فیلتر، جستوجو و نشانگذاری |
| تاریخچه کارها | چه کسی، کِی، چه چیزی را ثبت، ویرایش یا حذف کرد — با مقدار قبلی و جدید |
| گزارشها | گزارشهای تحلیلی و صورت سود و زیان |
| اتاق فرمان | مدیریت حسابدارها، دسترسیها و رویدادها (فقط مدیر) |
| تنظیمات | نرخ، درصدها، گروههای اشخاص، پشتیبان |
نکته: دکمهٔ «ثبت سند» در منو نیست؛ از داخل کارت هر شخص باز میشود، چون هر سند به یک طرفحساب وصل است.
چند صفحه با هم: با Ctrl+کلیک روی هر گزینهٔ منو، آن صفحه در یک سربرگ تازه باز میشود و صفحهٔ فعلی بسته نمیشود. توضیح کامل در بخش ۲۳.
#آشنایی با محیط کیمیا
چهار صفحهٔ کلیدیِ محیط کار برای کسی که تازه با برنامه آشنا میشود:
- کتابخانهٔ دفترها: نخستین صفحه پس از باز شدن برنامه — کادر جستوجو، دو سربرگ جاری و مخفی، و فهرست دفترها که هرکدام یک حسابکتابِ مستقل با کد و نامِ خودش است (مثل «آبشده فروشی»، «بنکداری» و «تکفروشی»). جزئیات کار با چند دفتر در بخش ۱۲.۶ است.
- میز کار و قیمت آنلاین: نوار منوی بالا (سند، گزارش، خلاصه وضعیت، پنل ریالی)، پنل قیمت آنلاین (انس، مظنهٔ بازار تهران، طلای ۱۸، دلار و سکهها) با دکمهٔ انتقال به قیمت روز، و کارتهای میانبرِ اقساط مانده، چکهای قابل وصول و آبشدهٔ شرطی.
- خلاصه وضعیت: جدولِ ماندهحسابها و موجودیها بر حسب گرم ۷۵۰ و مبلغ — شرحِ کامل در بخش ۲۹.
- چند پنجره همزمان: باز نگهداشتنِ چند دفتر یا چند صفحه کنار هم برای ساعتهای شلوغ — بخش ۲۳.
#۲. مفهوم مانده: بدهکار و بستانکار
هر شخص یک مانده دارد که خلاصهٔ همهٔ داد و ستدهای اوست. این مانده در دو واحد جداگانه نگهداری میشود:
- ریال (پول نقد)
- طلای ۷۵۰ (گرم طلای نرمالشده به عیار ۷۵۰)
معنی دو کلمهٔ کلیدی:
- بدهکار (به ما): طرفحساب به ما بدهکار است. مثلاً جنس برده و پولش را نداده.
- بستانکار (از ما): ما به او بدهکاریم. مثلاً پول داده و هنوز جنس نگرفته.
مثال ساده: مشتری «رضا» ۵ گرم طلای ۷۵۰ میخرد و پولش را نمیدهد → رضا ۵ گرم به ما بدهکار میشود. فردا ۳ گرم پول میآورد → بدهیاش به ۲ گرم میرسد. همینطور برای ریال هم جدا حساب میشود.
#۳. سند چیست و چطور ثبت میشود
سند واحد اصلی ثبت هر رویداد مالی است. پنج نوع سند داریم:
| نوع سند | یعنی چه | جهت پیشفرض روی مانده |
|---|---|---|
| فروش | جنس به مشتری فروختی | طرف به تو بدهکار میشود |
| خرید | از کسی جنس خریدی | تو به او بدهکار میشوی |
| دریافت | پول/طلا گرفتی | بدهی طرف کم میشود |
| پرداخت | پول/طلا دادی | طلب طرف کم میشود |
| سایر | موارد خاص (بدون جهت پیشفرض) | با «تشخیص» ردیف تعیین میشود |
هر سند:
- یک شمارهٔ یکتا دارد.
- میتواند چند ردیف داشته باشد. هر ردیف یکی از این نوعهاست: طلا (وزنی)، نقد/ریالی، سکه (تعدادی)، اجرت/خدمات، تخفیف.
قاعدهٔ مهم: هر فاکتور را در یک شمارهٔ سند جداگانه ثبت کن تا حسابها قاطی نشوند.
برای کنترلِ سند با ترازو پیش از ذخیره — جمعِ چند ردیف انتخابی و پنلِ ورود و خروج — بخش ۲۵ را ببین.
مثال یک سند فروش با چند ردیف:
| نوع ردیف | توضیح | مقدار |
|---|---|---|
| طلا (وزنی) | یک النگو | ۱۰ گرم، عیار ۷۵۰ |
| اجرت/خدمات | اجرت ساخت | ۵٬۰۰۰٬۰۰۰ ریال |
| تخفیف | تخفیف مشتری | ۲٬۰۰۰٬۰۰۰ ریال |
#۴. ستون «تشخیص»: قلب مدل کیمیا
هر ردیفِ سند یک ستون «تشخیص» دارد. این ستون تعیین میکند آن ردیف روی مانده «به کدام سمت» اثر بگذارد. چهار حالت دارد:
| تشخیص | چه زمانی | اثر روی مانده |
|---|---|---|
| عادی | حالت معمول | همان جهت پیشفرض نوع سند |
| مرجوع | جنس/پول برگشت خورد | جهت سند برعکس میشود |
| خروج | فقط در سند «سایر» — خروج ارزش (هزینه/ضرر) | همیشه منفی |
| ورود | فقط در سند «سایر» — ورود ارزش (درآمد/سود) | همیشه مثبت |
#چرا «مرجوع» یک ردیف است، نه یک نوع سند جدا؟
چون در واقعیت مغازه، برگشت جنس معمولاً بخشی از یک فاکتور است، نه یک سند مستقل. با «تشخیص» میتوانی در همان سند فروش، یک ردیف را «مرجوع» بزنی و آن ردیف جهت عکس میگیرد.
مثال «مرجوع»: در سند فروش، مشتری ۱۰ گرم خرید ولی ۲ گرم را پس آورد:
- ردیف ۱: طلا ۱۰ گرم — تشخیص عادی → ۱۰ گرم به ما بدهکار
- ردیف ۲: طلا ۲ گرم — تشخیص مرجوع → ۲ گرم از بدهی کم میشود
- نتیجه: ۸ گرم بدهی خالص.
مثال «خروج/ورود» در سند «سایر»: اینها برای حسابهای داخلی و مواردی است که جهت پیشفرض ندارند:
- ثبت یک ضرر/کسری صندوق → ردیف با تشخیص خروج (منفی)
- ثبت یک درآمد جانبی/اضافهآمدن → ردیف با تشخیص ورود (مثبت)
خیالت راحت باشد: برای ردیفهای «عادی» و «مرجوع» رفتار دقیقاً مثل قبل است؛ فقط «خروج/ورود» در سند «سایر» قابلیت تازه است. اسناد قدیمی هیچ تغییری نمیکنند.
#۵. ستون «شرح» و «بابت»
این دو ستون فقط اطلاعاتیاند و روی هیچ عددی اثر نمیگذارند؛ فقط برای شفافیت و گزارشگیریاند.
#شرح (کد سیستمی)
یک کد استاندارد که جنس/ابزار ردیف را مشخص میکند و به نوع ردیف وابسته است:
| نوع ردیف | کدهای شرح |
|---|---|
| طلا | ۱ آبشده · ۲ متفرقه · ۳ آبشده شرطی · ۹ اضافه · ۱۰ متفرقه سالم |
| نقد/اجرت | ۵ نقدی · ۶ چک · ۷ حواله |
| تخفیف | ۸ کسر |
اگر نوع ردیف را عوض کنی و کد قبلی به نوع جدید نخورَد، کد خودکار پاک میشود.
سه کد استثنا هستند و کارِ عملی میکنند: - ۶ چک → زیرِ ردیف یک نوارِ «مشخصات چک» باز میکند و آن ردیف را وارد دفتر چک میکند. - ۸ کسر → ردیف را به مبلغِ منفی (تخفیف) تبدیل میکند. برای اصلاحِ حساب وقتی چیزی فیزیکی جابهجا نشده — تهحسابِ باقیمانده، تخفیف، کارمزدِ بانکی — همین کد را بزن. سرراستترین راهش دو میانبرِ پای سند است: کسر و اضافه. - ۹ اضافه → قرینهٔ «کسر» است، ولی روی وزن: طرفِ حساب را به اندازهٔ یک وزن بستانکار میکند بدون اینکه یک سوت طلا وارد مغازه شود. پس در کاردکس و پنلِ ورود ـ خروج و کارکردِ معاملات نمیآید، و در سود و زیان بهعنوانِ زیانِ طلا مینشیند. کاربردِ اصلیاش اجارهٔ طلا است.
#بابت
یک متن آزاد که علتِ ردیف را میگوید. هنگام تایپ، پیشنهادهای رایج میآید: بدهی قبلی، علیالحساب، تسویه حساب، بیعانه، اجرت، امانت، کرایه، قرض…
مثال: یک ردیف دریافت ۵۰٬۰۰۰٬۰۰۰ ریالی با شرحِ «۶ چک» و بابتِ «علیالحساب» → یعنی این چک بابتِ علیالحساب گرفته شده. هیچ اثری روی مانده ندارد ولی در فاکتور و گزارش دیده میشود.
#۶. وزن ۷۵۰ و عیار
طلا با عیارهای مختلف (۱۸، ۲۱، ۲۴…) داد و ستد میشود. برای اینکه همهچیز قابلجمع باشد، همهٔ وزنها به یک عیار مبنا (پیشفرض ۷۵۰) تبدیل میشوند:
وزن ۷۵۰ = وزن × عیار ÷ عیار مبنا
مثال: ۱۰ گرم طلای عیار ۹۰۰ → ۱۰ × ۹۰۰ ÷ ۷۵۰ = ۱۲ گرم معادل ۷۵۰. پس در مانده ۱۲ گرم ثبت میشود، نه ۱۰.
#ستون «عیار شخصی»
کنارِ ستون عیار، یک ستون دومِ اختیاری هست: عیار شخصی — یعنی عیاری که با مشتری حساب میکنی، که میتواند با عیارِ واقعیِ جنس فرق داشته باشد (مثلاً متفرقهٔ ۷۴۰ که ۷۵۰ میفروشی). خالی گذاشتنش یعنی «همان عیارِ جنس» و رفتار مثل قبل است. → بخش ۲۴
#۷. مالیات سند فروش (فرمول جدید)
در پای سند فروش یک کارت طلایی قابلفعالسازی هست که مطابق فرمول جدید سازمان امور مالیاتی حساب میکند:
- طلای خام (وزن۷۵۰ × نرخ) → معاف از مالیات.
- سود فروشنده = درصد × (طلای خام + اجرت + سنگ).
- مالیات ارزش افزوده = درصد × (اجرت + سنگ + سود فروشنده) — فقط روی این اجزا، نه روی طلای خام.
درصدهای پیشفرضِ «سود فروشنده» و «مالیات ارزش افزوده» در تنظیمات قابل تغییرند. هنگام ثبت فروش، درصدهای مؤثر روی خود سند ذخیره میشوند؛ بنابراین تغییر تنظیمات امروز، فاکتور و گزارش مالیاتی گذشته را بازنویسی نمیکند.
مثال عددی: طلای خام ۱۰۰٬۰۰۰٬۰۰۰ + اجرت ۱۰٬۰۰۰٬۰۰۰، سود ۷٪، ارزش افزوده ۱۰٪:
- سود فروشنده = ۷٪ × (۱۰۰م + ۱۰م) = ۷٬۷۰۰٬۰۰۰
- ارزش افزوده = ۱۰٪ × (۱۰م + ۷٫۷م) = ۱٬۷۷۰٬۰۰۰
#پروفایل مالیاتی شخص و اولویت معافیتها (v110)
در فرم ساخت یا ویرایش شخص، کارت «پروفایل مالیاتی این شخص» مشخص میکند فروشهای تازهٔ او بهطور پیشفرض ارزش افزوده داشته باشند یا معاف باشند. این گزینه فقط نقطهٔ شروع سند جدید است و سه سطح مستقل دارد:
| سطح | کجا تنظیم میشود | کاربرد |
|---|---|---|
| جنس | تعریف جنس با گزینهٔ «ارزش افزوده ندارد» | برای قلمهایی مانند سکهٔ پارسیان؛ فقط همان ردیف معاف است. |
| شخص | کارت پروفایل مالیاتی در فرم شخص | پیشفرض همهٔ فروشهای تازهٔ این طرفحساب. |
| سند | کلید مالیات در کارت پایین فاکتور | استثنا فقط برای همان فاکتور؛ بر پروفایل شخص مقدم است. |
اگر شخص معمولاً معاف است اما این فروش باید مشمول باشد، کلید مالیات همان سند را روشن کنید. اگر شخص معمولاً مشمول است اما یک فروش خاص معاف است، کلید را خاموش کنید. این تغییر پروفایل شخص یا فاکتورهای دیگر را عوض نمیکند. پس از ثبت نیز وضعیت و منبع مالیات روی سند مهر میشود؛ تغییر بعدی پروفایل شخص، اسناد قبلی را دست نمیزند.
#ستون مالیات در فاکتور چاپی
از تنظیمات ← مرکز چاپ فاکتور ← ستونها، گزینهٔ مالیات را روشن کنید. سهم مالیات هر ردیف در ستون جدا دیده میشود؛ ردیف معاف خط تیره دارد و جمع ستون همیشه با جمع مالیات کارت سند برابر است. این ستون پیشفرض خاموش است تا قالب فعلی فاکتورهای شما بدون انتخاب خودتان تغییر نکند.
#مرکز مالیات در گزارشها
در صفحهٔ گزارشها، کارت مرکز مالیات بر اساس بازهٔ انتخابشده این شاخصها را نشان میدهد:
- مالیات دریافتی؛
- پایهٔ مشمول و پایهٔ معاف؛
- فروش ناخالص و تعداد فاکتورهای مشمول، معاف و ترکیبی؛
- فهرست آخرین اسناد با امکان بازکردن مستقیم فاکتور.
مالیات دریافتشده تا زمان واریز، بدهی مالیاتی فروشگاه است. پرداخت به سازمان امور مالیاتی را در هزینهها با دستهٔ بیمه و مالیات ثبت کنید. چون این دسته ممکن است هزینهٔ بیمه را هم در خود داشته باشد، مرکز مالیات آن را خودکار از بدهی کم نمیکند تا رقم اشتباه نسازد.
دکمهٔ «خروجی سالانه TTMS / CSV» سال شمسی را میگیرد و فایل UTF-8 شامل شماره و تاریخ سند، مشخصات خریدار، فروش ناخالص، پایهٔ مشمول، پایهٔ معاف، مالیات و وضعیت را میسازد. فایل برای بازبینی در Excel و انتقال به فرایند TTMS آماده است. قالب اختصاصی یا باینریِ نسخههای قدیمی TTMS ممکن است متفاوت باشد و بدون نمونهٔ رسمی همان نسخه، سازگاری مستقیم آن تضمین نمیشود.
#۸. حساب بانکی و کارتخوان (پوز)
#حساب بانکی
حسابهای بانکی فروشگاه با ارز، شماره حساب، تلفن و ماندهٔ اول دوره تعریف میشوند.
- «بدهکار به ما» = موجودی مثبت شما · «بستانکار از ما» = بدهی شما به بانک.
- فقط حسابهای مرتبط با مغازه اینجا بیایند؛ حسابِ شخصی جای دیگری ثبت میشود.
حسابِ دستهچک را مستقل بساز. اگر بانک برایت دستهچک صادر کرده، آن حساب را جدا تعریف کن — حتی اگر در همان بانکی است که حسابهای دیگر داری. موجودیِ این حساب باید فقط پاسخگویِ چکها باشد تا دفتر چک بتواند قبل از هر «پاس شد» بگوید موجودی کم میآید یا نه. پر کردنِ این حساب با یک سندِ پرداختِ نقدی از صندوق یا یک حواله از حسابِ دیگر انجام میشود.
#کارتخوان (پوز)
پول کارتخوان لحظهای به حساب نمینشیند؛ معمولاً فردای همان روز یکجا حواله میشود. برای اینکه موجودی درست بماند:
- یک حساب بانکی بساز و تیک «حساب کارتخوان (پوز)» را بزن.
- وقتی مشتری با کارت میکشد، در سند دریافت، «حساب مقصد» را همان حساب پوز بگذار.
- در نمای «حساب بانکی»، پنل کارتخوانها مبلغِ در انتظار تسویهٔ هر پوز را نشان میدهد.
- فردا با دکمهٔ «تسویه به حساب»، مبلغ یکجا به حساب اصلی منتقل میشود. سامانه یک جفت سند قفلشده (پرداخت از پوز + دریافت به حساب مقصد) میسازد و موجودی پوز صفر میشود.
- آخرین تسویهها فهرست میشوند و هر کدام قابل لغو است (جفت سند حذف و موجودی برمیگردد).
#۹. حوالهٔ دوطرفه
انتقال مستقیم بین دو شخص: از مبدأ کم و به مقصد اضافه میشود، بدون تغییر موجودی صندوق. هر حواله = یک جفت سند قفلشده (پرداخت روی مبدأ + دریافت روی مقصد). دکمهٔ میانبر «تسویه» بدهی/طلب طرفین را خودش پیشنهاد میدهد.
#حواله معامله نیست
این جملهٔ کوتاه، کلِ منطقِ حواله است: حواله جابهجاییِ یک طلب است، نه خرید و فروش. طلا یا پولی که حواله میشود قیمتش قبلاً — در سندِ معاملهٔ اصلی — بسته شده. پس حواله:
- فی ندارد. جایی برای وارد کردنِ قیمت نیست، چون قیمتی بسته نمیشود.
- کارکرد نمیسازد. نه سود، نه زیان. جمعِ سیستم دستنخورده میماند.
- وضعیتِ بازِ مغازه را تکان نمیدهد. ریسکِ نوسان با جابهجا شدنِ طلا بینِ دو حساب نه کم میشود نه زیاد.
#ریالی یا طلا
بالای فرم دو دکمه هست: ریالی و طلا (گرم۷۵۰). با عوض کردنشان فیلدها هم عوض میشوند:
| دارایی | فیلدها | مثال |
|---|---|---|
| ریالی | مبلغ (﷼) | حوالهٔ ۹٬۹۹۲٬۰۰۰٬۰۰۰ ﷼ از مشتری به بنکدار |
| طلا | وزن (گرم) + عیار | حوالهٔ ۹۵ گرم۷۵۰ از یک بنکدار به بنکدارِ دیگر |
تعویضِ دارایی مبلغ را پاک میکند. عمدی است: ۹۹۹ میلیون ریال و ۹۹۹ گرم یک عدد نیستند و جا ماندنِ رقمِ قبلی خطای بیسروصدا میسازد.
#مثال ویدئو: حوالهٔ طلا بین دو بنکدار
آقای ابراهیمی ۶۱۷٫۳۲ گرم۷۵۰ طلبکار است. ۹۵ گرم از طلبش را به آقای عابدزاده حواله میکنی:
| پیش از حواله | پس از حواله | |
|---|---|---|
| ابراهیمی | ۶۱۷٫۳۲ گ۷۵۰ | ۵۲۲٫۳۲ گ۷۵۰ |
| عابدزاده | ۰ | ۹۵ گ۷۵۰ |
| کارکرد | — | ۰ |
| وضعیت باز | ۶۱۷٫۳۲ | ۶۱۷٫۳۲ (بیتغییر) |
#چرا با خرید/فروش ننویسیم
تا پیش از این فقط ریال حواله میشد، پس برای جابهجا کردنِ طلا بین دو حساب چارهای جز نوشتنِ یک «فروش» و یک «خرید» نبود. اندازهگیری شد که همین کار روی همان حوالهٔ ۹۵ گرمی چه میکند:
- طلا درست جابهجا میشود — تا اینجا فرقی ندارد.
- ولی چون خرید و فروش ذاتاً یک پایِ ریالی دارند، ۱٬۲۶۲٬۶۴۵٬۵۷۵ ریال بدهیِ ساختگی روی یک حساب و همان مقدار طلبِ ساختگی روی حسابِ دیگر مینشیند. پولی که هرگز جابهجا نشده.
- و اگر فقط یک طرف را بنویسی، علاوه بر آن، ۹۵ گرم وضعیتِ بازِ ساختگی هم میسازی؛ یعنی صفحهٔ «پوشش ریسک» ریسکی را گزارش میکند که وجود ندارد.
با حوالهٔ طلا هر دو عدد صفر میمانند.
#میانبر: حواله از روی مانده
در صفحهٔ اشخاص، ماندهٔ ریالی و ماندهٔ طلاییِ هر شخص که صفر نباشد خودش یک دکمه است. یک کلیک روی آن، فرمِ حواله را باز میکند با جهت و مبلغِ آماده:
- طلبکار (مانده مثبت) → مبدأ میشود؛ سندش «پرداخت». طلبش را جای دیگر میبری.
- بدهکار (مانده منفی) → مقصد میشود؛ سندش «دریافت». بدهیاش از جای دیگر تسویه میشود.
فقط کافی است طرفِ مقابل را انتخاب کنی. مبلغ کلِ مانده است و قابلِ ویرایش؛ وزنِ طلا تا سه رقمِ اعشار (میلیگرم) گرد میشود.
#نامِ طرفِ مقابل روی فاکتور
در تنظیمات گزینهای هست: «نامِ طرفِ مقابل در فاکتورِ چاپیِ حواله نیاید». وقتی از حسابِ یک بنکدار برای مشتری حواله میزنی، لازم نیست مشتری بداند پولش از کجا آمده. این گزینه فقط چاپ را عوض میکند — در ردیفِ سند و در همهٔ گزارشها نامِ طرفِ مقابل سرِ جایش میماند.
#ثبت حواله در سند باز یا سند جدید — v98
وقتی حوالهای ثبت میکنید، برنامه برای هر طرف جداگانه آخرین سندِ همنوعِ همان تاریخ را بررسی میکند. اگر سند هنوز چاپ یا بسته نشده باشد، ردیف حواله به همان سند اضافه میشود؛ سندی با تاریخ دیگر یا سندی که فاکتور آن چاپ شده باشد، قابل استفاده نیست و برای حواله سند تازه ساخته میشود. این تصمیم برای حوالهٔ ریالی و طلایی یکسان است.
در تنظیمات ← رفتار حواله گزینهٔ «ثبت هر حواله در سند جدید» قرار دارد. در حالت روشن، حتی سند همروز و باز نیز دستنخورده میماند و هر حواله در سند جدید ثبت میشود. خاموشبودن گزینه حالت پیشفرض و سریع روزانه است. در هر دو حالت، حواله همچنان جفتِ مرتبطِ پرداخت و دریافت با شناسهٔ مشترک است و طلا بدون فی و ریال بدون اثر ساختگی در سود ثبت میشود.
#مشخصات فیش روی دو سند مرتبط — v96
در فرم حواله میتوانید بانک مبدأ، شماره پیگیری و ساعت واریز را وارد کنید. این اطلاعات اختیاریاند، اما اگر وارد شوند روی هر دو سند مرتبط ذخیره و در چاپ همان سند نمایش داده میشوند؛ بنابراین رسیدی که از حساب مبدأ چاپ میکنید با رسید حساب مقصد یک مشخصات پیگیری دارد.
گزینهٔ پنهانکردن نام طرف مقابل فقط نام شخص را به «حواله» تبدیل میکند. بانک، شماره پیگیری و زمان واریز همچنان روی چاپ باقی میمانند تا رسید قابل پیگیری باشد، در حالی که اطلاعات طرف تجاری افشا نشود. ویرایش یکی از سندهای مرتبط نیز مشخصات فیش را همراه مبلغ، تاریخ و توضیح روی هر دو طرف بهروزرسانی میکند.
#۱۰. نوع حسابها، امانات، سرمایه و برداشت
این صفحه سه زبانه دارد:
- گروههای حساب: عنوانهای «نوع حساب» که موقع ساختن هر شخص انتخاب میشوند (مثل مشتری، همکار، کارگاه).
- امانات: حسابهای امانت که در لیست همکاران دیده نمیشوند.
- سرمایه و برداشت: حساب خودت و شرکا؛ برای هر شریک یک ٪ سهم از سود تعیین میکنی.
برداشت شخصی هر جا ثبت شود، همیشه به نامِ یک شریک ثبت میشود و همیشه از سهمِ همان شریک کم میشود — نه از سود مغازه. دو راهِ ثبت دارید و هر دو به یک عدد میرسند: سندِ «سرمایه و برداشت» با تشخیصِ خروج، یا ردیفِ «مخارج مغازه» با تشخیصِ برداشت شخصی که آنجا هم نامِ شریک را میپرسد. جزئیات در «گزارش سهم شرکا» پایینِ همین بخش.
#نوع حساب فقط یک برچسب نیست — ماهیت (v41)
تا امروز «نوع حساب» فقط یک اسم بود که کنارِ شخص مینشست. حالا هر عنوان یک ماهیت دارد، و ماهیت یعنی رفتار: برنامه بر اساسِ آن تصمیم میگیرد سندِ آن شخص چطور باز شود، سودش شمرده شود یا نه، و اسمش در کدام فهرستها بیاید.
بالای زبانهٔ «گروههای حساب» یک تختهٔ ماهیتها با هشت کارت میبینید. هر کارت رنگ و آیکنِ خودش را دارد، عنوانهایی که زیرش نشستهاند را نشان میدهد و تعداد حسابهایش را میگوید. روی هر کارت کلیک کنید تا فهرستِ همان حسابها باز شود.
| ماهیت | یعنی چه |
|---|---|
| بنکداری | حالتِ عادی و پیشفرض. هیچ رفتارِ ویژهای ندارد — همکار، بنکدار، کارگاه، مشتریِ عمده. |
| تکفروشی | مشتریِ سرِ پیشخوان. سند با قیمت هر گرم باز میشود. |
| بانک | فقط برای حسابهای بانکیِ خودِ مغازه. |
| هزینهها | طرفحسابی که خرجِ مغازه است (اجارهدهنده، پیمانکار). |
| سرمایه و برداشت | حسابِ خودت و شرکا. از سود و زیان بیرون میماند. |
| ذوب | ذوبخانه و آبشده. |
| حساب داخلی | نقلوانتقالِ داخلیِ خودت، نه معامله با بیرون. |
| امانات | امانتها؛ از فهرستِ روزمرهٔ اشخاص پنهان میشوند تا شلوغی نکنند. |
چطور ماهیت را ست کنم: در جدولِ همان زبانه، جلوی هر عنوان یک انتخابگرِ ماهیت هست. انتخاب کنید، تمام. عنوانِ تازه را هم میتوانید همانجا با ماهیتش بسازید. دکمهٔ نوعهای استاندارد هر هشت عنوانِ مرجع را که ندارید اضافه میکند و ماهیتشان را مینشاند — عنوانهای خودتان دست نمیخورند. دکمهٔ خروجی اکسل هم فهرستِ کاملِ حسابها با نوع، ماهیت، مانده و وضعیت را میدهد.
دفترِ فعلیِ شما تکان نمیخورد. تا وقتی خودتان ماهیتی ست نکنید، همهٔ عنوانها «بنکداری» یعنی بیرفتار میمانند و هیچ عددی عوض نمیشود. برنامه از روی شباهتِ اسم حدس نمیزند — «سرمایهگذار» خودبهخود «سرمایه و برداشت» نمیشود.
#برداشت شخصی هزینهٔ مغازه نیست
اگر ۵۰ میلیون از صندوق بردارید و آن را مثل یک فروشِ معمولی ثبت کنید، گزارشِ سود و زیان فکر میکند مغازه معامله کرده و سود یا زیانِ خیالی میسازد. پولی که مالک برمیدارد نه درآمد است نه هزینه؛ فقط سرمایه جابهجا شده.
عنوانِ حسابِ خودتان و شرکا را روی ماهیتِ سرمایه و برداشت بگذارید. از آن لحظه، اسنادِ آن حسابها:
- در کارکرد معاملات شمرده نمیشوند،
- در کارکرد اجناس شمرده نمیشوند،
- ولی ماندهٔ حساب و گزارشِ سهم شرکا همچنان کاملاً درست کار میکند.
یعنی برداشتتان جایی که باید دیده میشود و جایی که نباید، نمیشود.
#تکفروشی: سند با «قیمت هر گرم» باز میشود
مشتریِ سرِ پیشخوان به «مظنه» و «مثقال» کاری ندارد؛ میپرسد گرمی چند؟ پس وقتی شخصی با ماهیتِ تکفروشی انتخاب شود، سند خودش را با او تنظیم میکند:
- واحدِ قیمت روی گرم میرود، نه مظنه/مثقال.
- مالیات ارزش افزوده خودکار روشن میشود (فاکتورِ خردهفروشی مالیات دارد).
- بالای سند یک فیلدِ قیمت هر گرم میآید. عدد را یک بار بزنید؛ روی همهٔ ردیفهای طلایی که هنوز فی ندارند مینشیند و هر ردیفِ تازه هم با همان فی باز میشود.
هیچوقت انتخابِ شما را لگدمال نمیکند. اگر سند ردیفِ پرشده داشته باشد یا خودتان واحد را دستی عوض کرده باشید، برنامه دست نمیزند. ردیفی هم که فیِ دستی دارد با «قیمت هر گرم» بازنویسی نمیشود.
راهنمای زیرِ انتخابگر: موقعِ ساختن یا ویرایشِ شخص، زیرِ «نوع حساب» یک خطِ رنگی میگوید این نوع چه ماهیتی دارد و چه رفتاری با خودش میآورد — تا پیش از ذخیره بدانید چه چیزی میخرید.
#گزارش «سهم شرکا» (تقسیم سود — سبک کیمیا)
پایینِ زبانهٔ «سرمایه و برداشت»، یک بردِ مدرن سود مغازه را بین شرکا تقسیم میکند. جدول دقیقاً همان شکلی است که کیمیا نشان میدهد:
دو سطرِ اول میگویند چه چیزی تقسیم میشود — «خلاصه وضعیت — طلا» و «خلاصه وضعیت — ریال». همان دو عددِ صفحهٔ «خلاصه وضعیت»، بیکموکاست.
بعد هر شریک دو سطر دارد: یکی برای طلا (گرمِ ۷۵۰) و یکی برای ریال. تا پیش از این فقط یک سطرِ ریالی بود و برداشتِ طلایی هیچجا از سهم کم نمیشد.
| ستون | یعنی چه |
|---|---|
| ٪ | درصد سهم همان شریک از سود |
| برداشت / آورده | آنچه در طولِ دوره از مغازه بیرون برده (برداشت) یا از جیبش گذاشته (آورده) |
| سهم خالص | آنچه واقعاً دستش را میگیرد |
فرمول، همان که ویدئوی مرجع روی صفحه نشان میدهد:
سهم طلای هر شریک = ٪ او × کل وضعیت بر حسب طلا − برداشتِ طلایی او
سهم ریالی هر شریک = ٪ او × کل وضعیت ریالی − برداشتِ ریالی او
مثالِ خودِ ویدئو (عددبهعدد): استخر ۷۰۱٫۷۰ گرمِ ۷۵۰ و ۴٬۳۶۰٬۵۶۰٬۰۰۰ ریال. شریکِ اول ۷۰٪ → سهمِ طلا ۴۹۱٫۱۹ گرم و سهمِ ریالی ۳٬۰۵۲٬۳۹۲٬۰۰۰؛ چون ۳٬۴۰۰٬۰۰۰٬۰۰۰ برداشته، خالصش −۳۴۷٬۶۰۸٬۰۰۰ است یعنی بیش از سهمش برداشته و به مغازه بدهکار است. شریکِ دوم ۳۰٪ → سهمِ طلا ۲۱۰٫۵۱ گرم و سهمِ ریالی ۱٬۳۰۸٬۱۶۸٬۰۰۰؛ چون ۷۵۰٬۰۰۰٬۰۰۰ برداشته، ۵۵۸٬۱۶۸٬۰۰۰ طلبش میماند.
#برداشت از هر سه در خوانده میشود (v55)
این مهمترین تغییرِ این گزارش است. برداشتِ شخصی در پنل سه راهِ ثبت دارد و گزارش تا امروز فقط یکی از آن سه را میدید — یعنی کسی که راهنما را مو به مو اجرا کرده بود، برداشتش در گزارش صفر میماند و پنل به او میگفت هنوز کلِ سهمش را طلبکار است. حالا هر سه در شمرده میشوند:
| در | کجا ثبت میشود | چطور به شریک وصل میشود |
|---|---|---|
| ۱ | سندِ خروج روی حسابِ خودِ شریک در زبانهٔ «سرمایه و برداشت» | خودبهخود |
| ۲ | سندِ شخصی که نوعِ حسابش ماهیتِ سرمایه و برداشت دارد | در ویرایشِ شریک، فیلدِ «حسابِ شخصِ این شریک» را به آن شخص وصل کنید |
| ۳ | ردیفِ برداشت شخصی در صفحهٔ «مخارج مغازه» | همانجا فیلدِ «به نامِ کدام شریک؟» را پر کنید |
زیرِ جدول، برای هر شریک یک کارت هست که میگوید عددش از کدام در آمده — تا وقتی رقمی عجیب دیدید مجبور نباشید کلِ دفتر را بگردید.
آورده هم شمرده میشود. پولی که شریک از جیبش به مغازه میگذارد عکسِ برداشت است و سهمش را بالا میبرد. در هر دو در (سندِ «ورود» یا تشخیصِ «آورده به مغازه» در مخارج) ثبت میشود.
برداشتِ بیصاحب هشدار میگیرد. اگر ردیفِ «برداشت شخصی» بدونِ نامِ شریک ثبت شده باشد، بالای گزارش یک هشدارِ قرمز با مبلغِ دقیق و میانبرِ رفتن به «مخارج مغازه» میآید. آن مبلغ از سهمِ هیچکس کم نشده، چون معلوم نیست مالِ کیست.
#چرا برداشت، کلِ وضعیتِ مغازه را کم نمیکند
وقتی ۲۵۰ میلیون برمیدارید دو اتفاق همزمان میافتد: پول از صندوق/بانک کم میشود، و مغازه به همان اندازه از شما طلبکار میشود. این دو دقیقاً همدیگر را خنثی میکنند و کلِ وضعیت تکان نمیخورد — برداشت، ثروتِ مغازه را نمیسوزاند، فقط جابهجایش میکند.
به همین دلیل در «خلاصه وضعیت» ماندهٔ حسابهای سرمایه و برداشت در ستونِ طلبِ مغازه مینشیند، نه بدهی.
اصلاحِ v55: تا نسخهٔ پیش، علامتِ ماندهٔ حسابهای امانات و سرمایه و برداشت وارونه بود: سندِ خروج ماندهٔ منفی میساخت و «خلاصه وضعیت» آن را بدهی میخواند. یعنی برداشت دو بار از وضعیتِ مغازه کم میشد — یک بار از صندوق، یک بار در ستونِ بدهی. حالا مثبت یعنی بدهکار (طلبِ مغازه) و منفی یعنی بستانکار، همراستا با تهحسابِ اول دوره و برچسبِ خودِ جدول. اگر در این دو زبانه حسابِ گردشدار دارید، عددشان با این نسخه علامت عوض میکند و درست میشود — یک بار نگاهشان کنید.
#۱۱. مخارج مغازه و حساب داخلی
دفترِ داخلیِ مخارج، هماهنگ با همان مدل تشخیصِ خروج/ورود اسناد. اینجا هزینههای روزمرهٔ مغازه و حسابوکتاب داخلی را ثبت میکنی.
#سه نوع تشخیص در مخارج
| تشخیص | یعنی چه | اثر روی سود |
|---|---|---|
| ▼ خروج | هزینهٔ عملیاتی (اجاره، حقوق، قبض…) | از سود خالص کم میشود |
| ▲ ورود | برگشت هزینه یا درآمد جانبی | به سود خالص اضافه میشود (مخارج را کم میکند) |
| برداشت شخصی | برداشت مالک/شرکا از صندوق، یا آوردهای که از جیبش میگذارد | جدا نگه داشته میشود، روی سود و زیان اثر ندارد — ولی از سهمِ همان شریک کم (یا زیاد) میشود |
#برداشت شخصی همیشه صاحب دارد (v55)
وقتی تشخیص را روی برداشت شخصی بگذارید، یک پنجرهٔ بنفش باز میشود و دو چیز میپرسد:
- برداشت از مغازه یا آورده به مغازه — آورده عکسِ برداشت است؛ سهمِ شریک را بالا میبرد و اگر حوالهای باشد، سندِ بانکیِ جفتشدهاش دریافت میشود نه پرداخت.
- به نامِ کدام شریک؟ — از فهرستِ شرکای زبانهٔ «سرمایه و برداشت» انتخاب میشود.
نامِ شریک در جدولِ مخارج کنارِ «بابت» دیده میشود. اگر ردیفی بدونِ نام باشد، همانجا با برچسبِ قرمزِ «بدونِ شریک» علامت میخورد و در «گزارش سهم شرکا» هم هشدار میگیرد — چون مبلغی که معلوم نیست مالِ کیست، از سهمِ هیچکس کم نمیشود.
شاخصِ بالای صفحه برداشت شخصیِ خالص را نشان میدهد: برداشت منهای آورده.
#فیلدهای هر مورد
تاریخ · مبلغ · بابت (اجباری، با پیشنهاد خودکار) · دسته · روش پرداخت (نقد/حواله/چک/کارت) · شرح. برای برداشت شخصی، شریک و جهتِ برداشت/آورده هم پرسیده میشود.
اگر روش حواله یا کارت باشد، حساب بانکی را هم انتخاب کن. پنل همزمان دو اثر جدا را ثبت میکند:
- خودِ رکورد مخارج، سود خالص را کم میکند؛
- سند بانکیِ جفتشده، موجودی همان حساب را کم میکند.
برای ▲ ورود (برگشت هزینه)، جهت هر دو اثر برعکس است: مخارج کم میشود و مبلغ به حساب بانکی انتخابی برمیگردد. حساب دریافتکننده لازم نیست همان حسابی باشد که هزینه ابتدا از آن پرداخت شده بود. ویرایش یا حذف مخارج، سند بانکیِ جفتشده را نیز هماهنگ میکند؛ بنابراین مبلغ دوبار محاسبه نمیشود و رد عملیات باقی میماند.
دستههای آماده: اجاره، حقوق و دستمزد، آب/برق/گاز، اینترنت و تلفن، تبلیغات، حمل و نقل، ملزومات و اداری، تعمیر و نگهداری، بیمه و مالیات، متفرقه.
#گزارش مخارج
- چهار شاخص (KPI): مخارج عملیاتی · برداشت شخصیِ خالص · تعداد اقلام · بیشترین بابت/دسته.
- تفکیک قابل جابهجایی: با یک کلید بین «بر اساس بابت» و «بر اساس دسته» جابهجا شو.
- فیلتر بازه: این ماه / ۳۰ روز / امسال / همه.
#چطور حساب میشود
مخارج عملیاتی = مجموع «خروج» − مجموع «ورود» (برداشت شخصی در این جمع نیست)
برداشت شخصیِ خالص = مجموع «برداشت» − مجموع «آورده» (به تفکیکِ شریک)
مثال یک ماه:
- اجاره ۲۰م (خروج) + قبض برق ۳م (خروج) + برگشت بیعانهٔ اجاره ۵م (ورود) → مخارج عملیاتی = ۲۰ + ۳ − ۵ = ۱۸م
- برداشت شخصیِ مالک ۱۰م و آوردهٔ ۴م به نامِ او → برداشت خالص = ۶م؛ جدا از ۱۸م میماند، سود خالص را کم نمیکند و در «سهم شرکا» از سهمِ همان مالک کسر میشود.
#ترجمهٔ خودکار هزینهٔ ریالی به طلا در خلاصه وضعیت (v100)
در طلافروشی نگهداشتن یک عددِ ریالی بهتنهایی واقعیت مغازه را نشان نمیدهد. از این نسخه، وقتی هزینهٔ عملیاتی را به ریال ثبت میکنید، خلاصه وضعیت یک کارت شفاف با عنوان «ترجمهٔ خودکار ریال به طلا» نمایش میدهد و اثر خالص مخارج را با نرخ زندهٔ گرم ۷۵۰ به وزن طلا تبدیل میکند:
اثر طلایی مخارج = (جمع خروجها − جمع برگشت هزینهها) ÷ نرخ روز گرم ۷۵۰
برای نمونه، اگر ۴۵۰٬۰۰۰٬۰۰۰ ریال هزینه ثبت شود و نرخ روز هر گرم ۷۵۰ برابر ۱۰۰٬۰۰۰٬۰۰۰ ریال باشد، اثر خالص در خلاصه وضعیت منفی ۴٫۵۰۰ گرم ۷۵۰ است. لازم نیست برای این کار معاملهٔ طلا، سند تبدیل ریال به طلا یا ثبت دستی دیگری بسازید.
کارت جدید چهار نکته را یکجا روشن میکند:
- مجموع خروجهای عملیاتی و برگشت هزینهها؛
- نرخ روزی که برای ترجمه استفاده شده؛
- اثر خالص بر حسب گرم ۷۵۰؛
- سه مخارج اثرگذار اخیر، همراه تاریخ و روش پرداخت، با میانبر مستقیم به دفتر مخارج.
این کارت اثر حسابداری تازهای ثبت نمیکند و مبلغ را دوباره از وضعیت کم نمیکند؛ فقط منشأ عدد نهایی را قابلردیابی میسازد. حواله و کارت از سند بانکی جفتشده و چک از دفتر چک وارد وضعیت میشوند. برداشت شخصی نیز عمداً در این محاسبه نیست، چون هزینهٔ مغازه محسوب نمیشود.
#رابطه با سود خالص
سود خالص = (فروش − خرید + ارزش طلای انباشته) − مخارج عملیاتی
برداشت شخصی عمداً در این فرمول نیست — چون پول شخصی مالک است، نه هزینهٔ کسبوکار. جای درستش گزارش سهم شرکا است، نه سود و زیان.
سازگاری با گذشته: رکوردهای قدیمیِ هزینه که تشخیص ندارند، خودکار «خروجِ عملیاتی» فرض میشوند؛ پس گزارشهای قبلی هیچ تغییری نمیکنند.
#۱۲. گزارشها و سود و زیان
- انتخاب بازهٔ زمانی (این ماه / ۳۰ روز / امسال / همه).
این صفحه دربارهٔ پول است. اگر سؤالت دربارهٔ خودِ جنس است — «این قلم کِی آمد، کِی رفت، و چرا موجودیاش با ترازو نمیخواند؟» — سراغ گردش موجودی برو.
#بردِ سود و زیانِ کارتمحور (سبک کیمیا)
بالای صفحه، سودِ دوره در دو بُعد نمایش داده میشود — دقیقاً مثل کیمیا که «سود دورهٔ طلا» و «سود دورهٔ ریال» را جدا میبیند:
- هدرِ برجسته: «کل سود و زیان دوره» به ریال، و معادلش به حسب طلا (گرم۷۵۰).
- کارت سود دورهٔ طلا: طلای خالصِ انباشتهٔ دوره (خرید منهای فروش) و ارزش ریالیاش به نرخ روز.
- کارت سود دورهٔ ریال: مابهالتفاوت نقدی (فروش − خرید).
- کارت هزینههای عملیاتی: جمع مخارجِ دوره (بدون برداشت شخصی).
- کارت سود/زیان ناخالص: نتیجهٔ کل معاملات + مجموع فروش.
- رنگ: سود سبز، زیان قرمز، هزینه طلایی.
#صورت سود و زیان
زیر کارتها، صورتحساب کامل ردیفبهردیف میآید: درآمد فروش، بهای خرید، مابهالتفاوت نقدی، ارزش طلای انباشته، سود ناخالص، هزینههای عملیاتی و در پایان سود خالص.
فرمول: سود خالص = (فروش − خرید + ارزش طلای خالصِ انباشته به نرخ روزِ گرم۱۸) − هزینههای عملیاتی. اجرتِ ساخت داخل مبلغ فروش لحاظ شده است. برداشت شخصی در این فرمول نیست.
#کنترل خودکار صحت حسابداری (v103)
بالای صفحهٔ «سود و زیان و گزارشها» یک برد زنده با عنوان «کنترل خودکار» قرار دارد. این برد کاری را که قبلاً چند مرحله داشت خودکار انجام میدهد: «خلاصه وضعیت» را از ابتدای دفتر محاسبه میکند، «کل سود و زیان به طلا» را نیز از همان بازه میگیرد و هر دو را با یک نرخ گرم ۷۵۰ کنار هم میگذارد.
سه عدد همیشه همزمان دیده میشوند:
- سود و زیان از ابتدای دفتر؛
- کل وضعیت فعلی مغازه؛
- اختلاف این دو به گرم ۷۵۰، با حد پذیرش کمتر از یک گرم.
چهار کنترل قطعی نیز زیر اعداد اجرا میشود: وجود نرخ مشترک طلا، ارزِ بدون نرخ، سکهٔ بدون مبنای وزن و عیار، و معاملهٔ اثرگذارِ بدون فی. سبز بودن این کنترلها به معنی کامل بودن همان دادههای قابلسنجش است؛ جای شمارش واقعی ویترین، صندوق و چکها را نمیگیرد.
اگر اختلاف کمتر از یک گرم باشد برد حالت همخوان میگیرد. اگر مغایرت وجود داشته باشد، موارد قرمز در اولویت بررسی قرار میگیرند و همان مغایرت بهعنوان یک استثنای پراهمیت وارد کارتابل هوشمند میشود؛ هوش مصنوعی یا کارتابل هیچ عددی را اصلاح نمیکند. دو دکمه نیز مسیر را کوتاه میکنند:
- بازکردن خلاصه وضعیت برای کنترل مانده و دارایی فیزیکی؛
- دیدن ریز کارکرد از ابتدا برای رسیدن مستقیم به منشأ سود و زیان.
این مقایسه مستقل از بازهای است که برای گزارش روز/ماه انتخاب کردهاید و همیشه «از ابتدا» اجرا میشود؛ چون فقط سود انباشته را میتوان با وضعیت فعلی مغازه مقایسه کرد. نتیجه با تغییر سند، موجودی یا نرخ فوراً دوباره محاسبه میشود و تأیید دستی ذخیره نمیکند.
#کارکرد معاملات و تطبیق با خلاصه وضعیت
پایینِ صفحهٔ گزارشها، بخش «کارکرد معاملات» میگوید سودِ شما دقیقاً از کجا آمده است. مبنا یک جملهٔ ساده است:
هر معامله با نرخ روز سنجیده میشود. آنچه گرانتر از نرخ روز فروختهاید یا ارزانتر از نرخ روز خریدهاید، سودِ شماست.
فرمولها
| حالت | فرمول |
|---|---|
| فروش طلا | وزن۷۵۰ × (فی − نرخ روز) + اجرت |
| خرید طلا | وزن۷۵۰ × (نرخ روز − فی) |
| سکه | تعداد × (فی − ارزش روز سکه) — ارزش روز از وزن و عیارِ «انواع سکه» |
هر سه در یک عبارت خلاصه میشوند: سود = −ضریبِ جهت × وزن۷۵۰ × (فی − نرخ روز). چون ضریبِ جهت از ستون تشخیص میآید، ردیفهای مرجوع خودبهخود علامتِ برعکس میگیرند و سودِ ثبتشده را پس میدهند.
کارتهای کارکرد (بر اساس کدِ ستون «شرح»):
- کارکرد آبشده — کدهای ۱ و ۳ (آبشده و آبشده شرطی)
- کارکرد متفرقه — کدهای ۲ و ۱۰ (متفرقه و متفرقه سالم)
- کارکرد اجناس (ویترین) — ردیفهای طلای بدون کدِ شرح
- کارکرد سکه — ردیفهای سکه
هر کارت جهتِ خرید/فروش را جدا نشان میدهد با وزن (یا تعداد)، میانگین فی، اجرت و نتیجه. با نگهداشتنِ نشانگر روی هر عدد، فرمولش نمایش داده میشود.
اقلام دیگر — چیزهایی که معامله نیستند ولی روی وضعیت مغازه اثر میگذارند: سود عیار شخصی، سود فروشندهٔ فاکتور، مالیات ارزش افزودهٔ دریافتی، کسر و اضافه (کد ۸)، اضافه و اجارهٔ طلا، حساب داخلی و هزینههای عملیاتی.
جمعبندی — سه ستون: جمع کارکرد معاملات، جمع اقلام دیگر، و کل سود و زیان به طلا (گرم۷۵۰) که همان جمعِ کل تقسیم بر نرخ روز است.
جعبهٔ تراز — این سود چقدر به مظنه بند است؟ (v34)
بالای جعبهٔ تطبیق یک جعبهٔ دیگر آمده که به یک سؤالِ ساده جواب میدهد: عددی که بالا نوشته شده قطعی است یا فقط عکسِ لحظهایِ مظنهٔ امروز؟
پاسخ به یک چیز بستگی دارد: خالصِ وزنیِ دوره. اگر هرچه طلا فروختهاید همانقدر هم خریده باشید، خالص صفر است و مظنه هرجا برود سودِ دوره تکان نمیخورد — جعبه سبز میشود و مینویسد «ترازید». اما اگر خالص صفر نباشد، یعنی یک لنگهٔ معامله هنوز باز است:
| حالت | یعنی | مظنه بالا برود |
|---|---|---|
| خالص مثبت | بیشتر خریدهاید، طلا دستتان مانده | سودتان بیشتر میشود |
| خالص منفی | بیشتر فروختهاید، بدهکارِ وزنی هستید | زیانتان بیشتر میشود |
جعبه همانجا حساب میکند اگر مظنه ۱٪ بالا یا پایین برود این عدد چقدر جابهجا میشود، تا اندازهٔ ریسک را با چشم ببینید.
مثالِ معروفِ همین موضوع: ۵۰۰ گرمِ ۷۵۰ را وقتی مظنه ۸۲٫۶۷ بود فروختهاید و هنوز نخریدهاید. همان لحظه گزارش «زیان ۸٬۰۷۹٬۷۷۸» نشان میدهد؛ مظنه که به ۱۰۰ میرسد همان معامله «سود ۱۹٬۶۲۲٬۳۱۹» میشود. هیچ سندی عوض نشده — فقط شما تراز نبودهاید. اگر لنگهٔ دوم معامله بیرونِ بازهٔ انتخابی افتاده، بازهٔ بزرگتری بگیرید تا هر دو طرف دیده شوند. تا وقتی تراز نیستید، سودِ خرید و فروش را قطعی نگیرید.
جعبهٔ تطبیق — در بازهٔ «همه»، عددِ «کل سود و زیان به طلا» با «کل وضعیت بر حسب طلا»ی صفحهٔ خلاصه وضعیت مقایسه میشود. اگر اختلاف زیر یک گرم باشد، تراز است؛ یعنی کارکردِ شما دقیقاً وضعیتِ امروزِ مغازه را توضیح میدهد. اگر نه، محتملترین دلیلها فهرست میشود:
- موجودی انبار دستی نگهداری میشود و پس از خرید و فروش بهروز نشده است.
- فروش بدون موجودی — جنسی فروخته شده که در انبار نبوده.
- سرمایهٔ آورده یا برداشتِ شرکا ثبت نشده.
- ماندهٔ اول دوره یا موجودی اولیه وارد نشده.
- ارزهای بدون نرخ زنده در جمعِ ریالی نیامدهاند.
نکتههای واحد: «فی» و همهٔ مبالغ ریالیاند، ولی نرخ زندهٔ گرم۱۸ تومانی ذخیره میشود؛ مقایسه با marketRial() انجام میشود که همان نرخ ضربدر ۱۰ است. خلاصه وضعیت هم از همین تابع استفاده میکند تا دو گزارش هممبنا بمانند. تطبیق فقط در بازهٔ «همه» معنا دارد؛ در بازههای کوتاه، سودِ دوره با وضعیتِ انباشتهٔ مغازه قابل مقایسه نیست. اگر نرخ روز در دسترس نباشد، این بخش محاسبه نمیشود. سکههایی که نوعشان در «انواع سکه» تعریف نشده، ارزشگذاری نمیشوند و تعدادشان زیر جمعبندی گزارش میشود.
#کارکرد اجناس: سود از کجا میآید (v38)
درست زیرِ «کارکرد معاملات» بخشِ دیگری نشسته که به همان سؤال جوابِ متفاوتی میدهد. تفاوت را باید یک بار برای همیشه فهمید:
دو گزارش، دو مبنا
| گزارش | با چه چیزی میسنجد | به چه سؤالی جواب میدهد |
|---|---|---|
| کارکرد معاملات | نرخ روز | از بازار جلو زدم یا عقب ماندم؟ |
| کارکرد اجناس | فیِ دریافتی (پای خودت) | روی جنسی که خودم آوردهام، چقدر گرفتم؟ |
هیچکدام غلط نیست و هیچکدام جای دیگری را نمیگیرد. اولی مظنهمحور است و با بالا و پایین رفتنِ بازار تکان میخورد؛ دومی به بازار کاری ندارد و فقط میگوید فاصلهٔ درصدِ ورودی و درصدِ خروجیِ همان قلم چقدر بوده. برای همین هر دو کارت بالای خودشان مبنایشان را نوشتهاند.
فرمولِ ستونِ طلا
وزن۷۵۰ × (درصدِ این ردیف − درصدِ دریافتی) ÷ ۱۰۰
جنس با ٪۱۰ آمده و با ٪۱۵ رفته؟ روی ۲۰ گرم میشود ۲۰ × (۱۵−۱۰) ÷ ۱۰۰ = ۱ گرم سود. همان جنس اگر با ٪۸ برگردد، ۱۰ × (۸−۱۰) ÷ ۱۰۰ = ۰٫۲۰ گرم زیان است — یعنی کارخانه همهٔ ضرر را قبول نکرده و شما هم شریک شدهاید.
جهتِ ردیف از ستون تشخیص میآید، پس مرجوعی هیچ قاعدهٔ جداگانهای ندارد: علامتش خودبهخود برعکس میشود و سودِ ردیفِ اصلی را پس میدهد. برای همین هر ردیف کنارِ جفتِ خودش نشسته (فروش کنارِ خرید مرجوعی، پرداخت کنارِ دریافت مرجوعی) — این دو را باید با هم ببینید، نه جدا.
جنسی که تازه وارد شده سود ندارد. دریافتِ ۱۷٫۴۱۰ گرم النگو با ٪۱۰ در خلاصه وضعیت موجودی میسازد ولی در سود و زیان هیچ ردیفی ندارد: «نخالی آمده و نخالی رفته». سود لحظهای متولد میشود که همان جنس با درصدِ دیگری از مغازه بیرون برود.
ستونِ مبلغ جدا حساب میشود: وزن۷۵۰ × (فی − فیِ دریافتی) + اجرتِ ریالی. اجرتِ درصدی عمداً اینجا نمیآید، چون قبلاً در ستونِ طلا شمرده شده و دوبارهشماری میشد.
مهمترین درسِ این بخش — اجرت را ریالی گرفتید؟
خیلیها اجرت را ریالی میگیرند چون «مشتری متوجه نمیشود». آنوقت در این گزارش ستونِ طلا زیان نشان میدهد و ستونِ مبلغ دقیقاً همانقدر جلو میافتد. این اشتباه نیست:
اگر اجرت را ریالی بگیرید، ستونِ طلا زیان میدهد و ستونِ مبلغ همانقدر سود؛ کل سود و زیانِ شما به طلا تکان نمیخورد.
پس آن عددِ قرمزِ ستونِ طلا را بهتنهایی نخوانید. زیرِ جدول یادداشتی هست که همین را یادآوری میکند.
مالیات و عوارضِ ارزش افزوده هم در جمع میآید، چون:
مالیات تا وقتی پرداختش نکردهاید، سود شمرده میشود — پولش وارد حسابِ شما شده و تا روزِ پرداخت دستِ شماست.
جمعبندی سه عدد دارد: سودِ دورهٔ طلا، سودِ دورهٔ ریال، و کل به طلا که برابر است با سود دورهٔ طلا + سود دورهٔ ریال ÷ قیمت گرم۷۵۰. اگر نرخ روز در دسترس نباشد، تبدیل انجام نمیشود و فقط دو ستون جدا میمانند.
ردیفِ کمرنگ چیست؟ قلمی که «پای خودت»ی برایش ثبت نشده — نه در موجودی ابتدای دوره آمده و نه سندِ ورودی دارد. سودش با پایهٔ صفر حساب میشود که یعنی بیش از واقع. تعدادشان زیر جدول اعلام میشود؛ راهِ حلش وارد کردنِ فی و درصد در موجودی اجناس است. این گزارش ردیفبهردیف پیش میرود، نه سندبهسند؛ پس اگر یک سند چند قلم داشته باشد، هر قلم سودِ خودش را جدا نشان میدهد.
#مرکز بررسی کارکرد اجناس (v104)
بالای جدولهای «کارکرد اجناس» یک صف بررسی مدرن قرار دارد تا برای پیدا کردن علتِ عدد قرمز مجبور نباشید همهٔ ردیفها را یکییکی باز کنید. این صف از همان ردیفها و همان فرمول گزارش ساخته میشود و محاسبهٔ موازی ندارد.
ابتدا بازه را از بالای گزارش انتخاب کنید: امروز، ۷ روز اخیر، این ماه، ۳۰ روز اخیر، امسال یا همه. بازهٔ کوتاه برای پاسخ به سؤال «امروز کدام جنس سود یا زیان ساخت؟» مناسب است؛ برای قضاوت حسابداری دربارهٔ مرجوعی، بازهٔ «همه» یا دستکم بازهای را ببینید که فروش اصلی و برگشت هر دو داخل آن باشند.
مرکز بررسی، ردیفهای منفی را به چهار علت روشن تفکیک میکند:
| وضعیت | معنی | اقدام درست |
|---|---|---|
| پایهٔ جنس ناقص است | فی یا درصدِ ورودی در موجودی اولیه یا دفتر پیدا نشده است | پایهٔ جنس را در موجودی و سند ورودی کامل کنید؛ تا آن زمان عدد سود قابل اتکا نیست |
| اجرت خروج ثبت نشده | جنس با درصد وارد شده ولی ردیف فروش/پرداخت نه درصد دارد و نه اجرت ریالی | سند را باز کنید و با توافق واقعی کنترل کنید؛ برنامه چیزی را خودکار حدس یا اصلاح نمیکند |
| اجرت به ریال منتقل شده | ستون طلا زیان دارد اما سود ریالی آن را جبران کرده است | دو ستون و «کل به طلا» را با هم بخوانید؛ این حالت لزوماً خطا نیست |
| اثر مرجوعی | خرید یا پرداخت مرجوعی، سود ردیف اصلی را پس میدهد یا با فی متفاوت زیان میسازد | بازه را بزرگتر کنید و ردیف مرجوعی را کنار معاملهٔ اصلی بررسی کنید |
| زیان خالص نیازمند بررسی | پس از جمع طلا و معادل ریالی هنوز نتیجه منفی است | تخفیف، فیِ کمتر از پایه، توافق با طرفحساب یا اشتباه ثبت را در همان سند کنترل کنید |
دو شمارندهٔ بالای صف، موارد نیازمند بررسی را از موارد قابل توضیح جدا میکنند. حداکثر هشت مورد مهمتر بر اساس شدت و اندازهٔ اثر نمایش داده میشود و دکمهٔ سند شما را مستقیم به ثبت خام میبرد. رنگ تنها نشانه نیست و عنوان علت روی هر ردیف نوشته شده است؛ در موبایل هر مورد به کارت تکستونه و دکمهٔ تمامعرض تبدیل میشود.
اصل ایمنی: این مرکز فقط تشخیص و مسیر بررسی ارائه میکند. هیچ فی، درصد، مرجوعی یا سند مالی را خودکار تغییر نمیدهد.
#لنز گزارش کارکرد اجناس (v105)
بالای مرکز بررسی، بخش «گزارش را دقیقاً برای چه میخواهید؟» قرار گرفته است. این لنز همان محاسبات کارکرد اجناس را محدود میکند؛ گزارش یا فرمول تازهای در کنار موتور اصلی نمیسازد، بنابراین جمع ریزها و جمع نهایی از یک منبع هستند.
۱. جریان را انتخاب کنید:
- خروجی خالص شامل فروش و پرداخت است و خرید مرجوعی و دریافت مرجوعی را از همان جریان کم میکند.
- ورودی خالص شامل خرید و دریافت است و فروش مرجوعی و پرداخت مرجوعی را از همان جریان کم میکند.
- همه هر دو سمت را کنار هم نگه میدارد.
۲. دامنهٔ اجناس را محدود کنید:
| انتخاب | کاربرد |
|---|---|
| یک جنس | پاسخ به سؤال «این مدل مشخص در این بازه چقدر کارکرد داشته؟» |
| گروه جنس / شراکت | چند جنس مرتبط را با نام گروهی که در اطلاعات پایه ثبت کردهاید یکجا میآورد؛ برای مثال «شراکت با همکار» |
| سازنده | همهٔ جنسهایی را که سازندهٔ ثبتشدهٔ یکسان دارند کنار هم میگذارد تا سودآوری کارهای دریافتی از آن سازنده روشن شود |
گروه و سازنده از اطلاعات پایهٔ همان جنس خوانده میشوند. اگر گزینهای در فهرست دیده نمیشود، ابتدا وارد اطلاعات پایهٔ اجناس شوید و «گروه جنس» یا «سازندهٔ جنس» را کامل کنید. انتخاب نام شخص در اسناد، جای تعریف سازندهٔ جنس را نمیگیرد؛ چون ممکن است یک شخص چند نقش یا چند نوع کالا داشته باشد.
۳. شکل نتیجه را انتخاب کنید:
- بر اساس جنس همان جدولهای ردیفبهردیف فعلی را نگه میدارد.
- بر اساس شخص یک خلاصهٔ شخصبهشخص با تعداد ردیف، وزن ۷۵۰، سود طلا و سود مبلغ میسازد. این همان دادههای فیلترشده است، فقط بهجای نوع رویداد بر اساس طرفحساب جمع میشود.
تعداد ردیفهای واردشده در محاسبه زیر فیلترها بهصورت زنده اعلام میشود. اگر ترکیب انتخابشده دادهای نداشته باشد، پیام روشن نمایش داده میشود و دکمهٔ پاککردن فیلترها گزارش را به حالت کامل برمیگرداند. کنترلها در موبایل تکستونه، دارای هدف لمسی حداقل ۴۴ پیکسل و قابل استفاده با صفحهکلید هستند.
وقتی دامنهٔ جنس، گروه یا سازنده محدود شده است، مالیات کل اسناد به جمع فیلترشده اضافه نمیشود؛ چون مالیات سند را نمیتوان بدون حدس میان چند جنس تقسیم کرد.
#تأثیر نوسان طلا بر حساب اشخاص (v106)
در صفحهٔ سود و زیان و گزارشها، برد «تأثیر نوسان طلا بر حساب اشخاص» ماندهٔ جاری هر طرفحساب را از همان دفتر اصلی میخواند و با نرخ زندهٔ گرم ۷۵۰ میسنجد. این برد مانده یا موتور مالی جداگانهای نمیسازد.
زاویهٔ دید مهم است: عبارت «طلبکار/بدهکار با نرخ امروز» و نتیجهٔ مثبت یا منفی، وضعیت خود شخص را نشان میدهد. این عدد سود تحققیافتهٔ فروشگاه نیست و نباید با صورت سود و زیان معاملات جمع شود.
برای حساب سادهٔ طلا و ریال، معادل تسویهٔ امروز چنین است:
ماندهٔ ریال + ماندهٔ طلا × نرخ امروز گرم ۷۵۰
علامت ماندهها همان قرارداد همهٔ بخشهای برنامه است: مثبت یعنی شخص از فروشگاه طلب دارد و منفی یعنی شخص به فروشگاه بدهکار است. اگر ماندهٔ طلا و ریال خلافعلامت باشند، برد نرخ سربهسر را نیز از نسبت قدرمطلق ماندهٔ ریال به ماندهٔ طلا نشان میدهد. مقایسهٔ این نرخ با نرخ آنلاین روشن میکند بالا یا پایین رفتن طلا چگونه وضعیت تسویهٔ شخص را تغییر داده است. اگر فقط یک نوع مانده وجود داشته باشد، نرخ سربهسر معنی ندارد و برد صرفاً ارزش تسویهٔ امروز را نمایش میدهد.
| وضعیت ردیف | معنی |
|---|---|
| شخص با نرخ امروز طلبکار است | جمع معادل تسویه از دید شخص مثبت است |
| شخص با نرخ امروز بدهکار است | جمع معادل تسویه از دید شخص منفی است |
| تسویه با نرخ امروز | اختلاف معادل کمتر از یک ریال است |
| در انتظار نرخ زنده | حساب ماندهٔ طلا دارد، اما نرخ معتبر برای گرم ۷۵۰ در دسترس نیست |
| چنددارایی — تفکیک لازم | حساب علاوه بر طلا و ریال، سکه یا ارز دارد؛ اجزا جدا نشان داده میشوند تا یک عدد ساده و گمراهکننده ساخته نشود |
کنترلهای بالای برد برای رسیدن سریع به حساب موردنظر هستند:
- ماندهدارها اشخاص دارای هر نوع مانده را نشان میدهد؛ همهٔ اشخاص حسابهای تسویه را هم نگه میدارد.
- حداقل ۱۰۰ گرم فقط اشخاصی را میآورد که قدرمطلق ماندهٔ طلای آنها دستکم ۱۰۰ گرم است.
- فیلتر گروه شخص از گروه ثبتشده در اطلاعات پایه استفاده میکند.
- فیلتر دارایی ردیف میان طلا، ریال، سکه، ارز و حساب چنددارایی تفکیک میکند.
- جستوجو نام، کد، تلفن و عدد مانده را میپذیرد؛ با دکمهٔ مشاهدهٔ حساب کارت کامل همان شخص باز میشود.
رنگ فقط کمک بصری است و متن وضعیت همیشه کنار عدد نوشته میشود. کنترلها با صفحهکلید قابل استفادهاند و در موبایل به چیدمان تکستونه و دکمههای حداقل ۴۴ پیکسلی تبدیل میشوند.
اصل ایمنی: این برد فقط گزارش و تحلیل است؛ هیچ سند، تسویه، حواله یا اصلاح خودکاری ایجاد نمیکند. برای حساب چنددارایی، هر دارایی را با نرخ و مبنای توافقشدهٔ خودش بررسی کنید.
#ریز سود و زیان — دابلکلیک روی هر سطر (v41)
گزارشِ سود و زیان میگوید «اجناس — فروش: ۱۲۰ میلیون سود». سؤالِ بعدیِ هر مغازهداری همیشه یکی است: از کجا؟ کدام مشتری، کدام جنس، کدام روز؟ تا وقتی جوابِ این سؤال نباشد، عددِ گزارش فقط یک ادعاست.
روی هر سطرِ گزارش دو بار کلیک کنید. یک سربرگِ تازه باز میشود که همان سطر را ردیفبهردیف باز کرده است. گزارشِ اصلی بسته نمیشود — سربرگش سرِ جایش میماند و هر وقت خواستید برمیگردید.
کدام سطرها باز میشوند:
- کارکرد معاملات — هر سطرِ جهت (اجناس ← فروش، اجناس ← خرید، سکه، آبشده، …) و همچنین سطرِ جمعِ گروه که هر دو جهت را با هم میآورد.
- کارکرد اجناس — هم زبانهٔ بالای جدول، هم سطرِ جمعِ هر گروه.
- کسر و اضافه (کد ۸) و اضافه و اجارهٔ طلا (کد ۹) در فهرستِ اقلامِ غیرمعاملاتی.
این سطرها نشانگرِ ماوس را به ذرهبین عوض میکنند و با عبورِ ماوس روشن میشوند؛ زبانهٔ کارکرد اجناس هم گوشهاش نشانِ ⤢ میگیرد.
در جدولِ ریز چه میبینید: تاریخ، نام طرفحساب، جنس یا تشخیص، وزن و فی و اجرت، سودِ همان ردیف، و ستونِ آخر ترازِ تجمعی — یعنی تا این ردیف جمعِ سود چقدر شده. همین ستون است که نشان میدهد سودِ ماه کجا جهید و کجا خوابید.
دوباره دابلکلیک، این بار روی خودِ ردیف → همان سندِ اصلی باز میشود. یعنی از عددِ گزارش تا سندِ خام، دو دابلکلیک فاصله است.
چرا عددِ ریز همیشه با عددِ خلاصه یکی است. جدولِ ریز گزارش را دوباره حساب نمیکند؛ هر دو از یک تابع بیرون میآیند و خلاصه فقط جمعِ همان ردیفهاست. اگر روزی جمعِ ریز با سطرِ خلاصه فرق کرد یعنی باگ داریم، نه اینکه «دو گزارش دو جور حساب میکنند».
#کسر و اضافه: بستنِ مانده بدون جابهجاییِ پول (v39)
نسخهٔ تصویریِ این آموزش با مثالهای اختلاف حساب، هزینهٔ بانکی، اجرت تعمیرات، اجرت حمل و تفاوت شمش در صفحهٔ «کسر و اضافه در کیمیا» آمده است.
با یک طرفحساب دو جنس معامله کردهاید، بخشی از پولش حواله شده، بخشی نقدی، و آخرِ کار ۸۵۴٬۰۰۰ ریال تهحساب مانده که نه او میآورَد و نه شما دنبالش میروید. این ردیف را با چه سندی میبندید؟
نه با خرید و فروش. خرید و فروش یعنی جنسی جابهجا شده و مظنه و فیِ طلا در کار است — اینجا هیچکدام نیست. نه با دریافتِ نقدی، چون قرار نیست پولی فیزیکی گرفته شود و صندوق نباید تکان بخورد. نه با دریافتِ حواله یا چک، چون چیزی به حساب شما نمیآید.
کد ۸ «کسر و اضافه» دقیقاً برای همین است: ردیفی که فقط ماندهٔ حساب را اصلاح میکند و هیچ چیزِ فیزیکی — نه طلا، نه پول، نه برگهٔ چک — جابهجا نمیکند.
دو دکمهٔ میانبر، پای هر سند
تا وقتی ماندهٔ نقدیِ طرف حساب پس از این سند صفر نباشد، زیرِ کارتهای مانده دو دکمهٔ کمرنگ میآید:
| دکمه | چه میکند |
|---|---|
| بخشیدن خرده | فقط چند رقمِ سمت راستِ مانده را صفر میکند — تهحسابِ کوچک |
| تسویهٔ کامل | کلِ ماندهٔ نقدی را با یک ردیف صفر میکند |
هر دو مبلغشان را روی خودِ دکمه نوشتهاند، پس پیش از کلیک میدانید چه اتفاقی میافتد. برای حالتهای دیگر (مبلغِ دلخواه، درصدی) دکمهٔ «کسر و اضافه (کد ۸)» فرمِ کامل را باز میکند.
«چند رقم از سمت راست صفر شود؟» — تنظیمِ خرده
مبلغِ «خرده» یک قاعدهٔ ساده دارد: باقیماندهٔ مانده بر ۱۰ به توانِ همان تعداد رقم. با تنظیمِ ۴ رقم، از ماندهٔ ۸۵۴٬۰۰۰ فقط ۴٬۰۰۰ بخشیده میشود و ۸۵۰٬۰۰۰ سرِ جایش میماند؛ اگر همان تنظیم را ۶ کنید، کلِ ۸۵۴٬۰۰۰ میرود و مانده صفر میشود. این عدد در تنظیمات ← تخفیف مبلغ از راست (رقم) است و پیشفرضش ۴ است. کنارش، حداکثرِ مبلغِ بخشیدنی هم نشان داده میشود تا لازم نباشد در ذهن توان حساب کنید.
جهت: دادم یا گرفتم؟
لازم نیست بین «دریافت» و «پرداخت» تصمیم بگیرید؛ برنامه از روی خودِ مانده حدس میزند و در فرم هم قابلِ تغییر است:
- طرف بدهکار بود ← تخفیف دادم. او را بستانکار کردهاید، پس برای مغازه زیان است.
- طرف طلبکار بود ← تخفیف گرفتم (کسر). او از طلبش گذشته، پس برای مغازه سود است.
ردیفِ ثبتشده همین را روی خودش مینویسد: نوارِ قرمز و مبلغِ منفی برای تخفیفِ دادهشده، نوارِ سبز و مبلغِ مثبت برای کسرِ گرفتهشده. لازم نیست برای فهمیدنِ جهت گزارش باز کنید.
قاعدهای که باید حفظ باشید: دریافتِ کد ۸ زیان است و پرداختِ کد ۸ سود.
در سود و زیان کجا مینشیند
در بخشِ اقلامِ دیگر خطی با عنوانِ «کسر و اضافه (کد ۸)» ساخته میشود که جمعِ همهٔ این ردیفهاست: تخفیفهای دادهشده منفی و کسرهای گرفتهشده مثبت. اگر یک تخفیفِ ۸۵۴٬۰۰۰ ریالی داده باشید، دقیقاً همان عدد بهعنوانِ زیان اینجا میآید — نه در کارکردِ معاملات، چون معاملهای در کار نبوده.
همزمان خلاصه وضعیت هم تکان میخورد: ماندهٔ ریالیِ طرف حساب به همان اندازه بسته میشود، در حالی که وزنِ طلا و موجودیِ صندوق دستنخورده میمانند.
#کشیدن کارت: بستنِ تهحساب با کارتخوان (v40)
مشتری جنس را برده، بخشی از پولش نقد بوده، مقداریاش را تخفیف دادهاید، و حالا ۳۱٬۰۰۰٬۰۰۰ مانده که قرار است همانجا پای دخل با کارت بدهد. لازم نیست سند را ببندید و جای دیگری بروید: پای هر سندی که ماندهٔ باز دارد، کنارِ دکمههای کسر و اضافه، دکمهٔ «کشیدن کارت» هست — یا از صفحهکلید <kbd>Ctrl</kbd>+<kbd>K</kbd>.
مهمترین قاعدهٔ کارتخوان: پولی که امروز کارت کشیده میشود امشب به حسابتان نمینشیند. بانک همهٔ کارتکشیهای امروزِ شما را فردا یکجا در یک حواله واریز میکند. پس اگر کارت را مستقیم روی حسابِ اصلی بزنید، امروز عددِ برنامه از عددِ بانک جلو میافتد و پرینتِ بانک با دفترتان نمیخوانَد.
یکبار برای همیشه: حسابِ پوز بسازید
در حسابهای بانکی یک حسابِ جدید به نامِ مثلاً «پوز ملت» بسازید و تیکِ کارتخوان (پوز) را بزنید. این حساب یک انبارِ موقتِ پول است، نه حسابِ واقعی. همین یک بار ساخته میشود.
در سند چه اتفاقی میافتد
پنجرهٔ «کشیدن کارت» سه چیز را از قبل برایتان پر میکند و پیش از ثبت هم نشانتان میدهد:
| بخش | چه میکند |
|---|---|
| جهت | از روی خودِ مانده حدس میزند — بدهکار بود «مشتری کارت میکشد»، طلبکار بود «بازگشت به کارتِ مشتری» |
| دستگاه کارتخوان | کارتِ هر دستگاه، با مبلغی که همین حالا رویش در انتظارِ حواله است |
| مبلغ | کلِ ماندهٔ باز، آماده؛ میتوانید کمترش کنید |
زیرِ فرم پیشنمایشِ زنده میگوید ماندهٔ مشتری به کجا میرسد، موجودیِ پوز از چه به چه میرود، و یک خطِ ثابت: صندوق و حسابِ اصلی دست نمیخورَد.
ردیفِ ثبتشده در جدولِ سند نوارِ بنفشِ خودش را میگیرد، مقصدِ پول («به پوز ملت») را روی خودش مینویسد، و پس از ذخیره دکمهٔ «نمایش سند مرتبط» دارد که مستقیم شما را به سندِ سمتِ پوز میبرد. پیش از ذخیره بهجای دکمه نوشته میشود «پس از ذخیره»، چون هنوز سندی ساخته نشده.
فردا: یک حواله، نه ده تا
صبحِ روزِ بعد به حسابهای بانکی ← پوز ملت بروید. موجودیاش جمعِ همهٔ کارتهای دیروز است — مثلاً ۸۰٬۰۹۷٬۰۰۰. دکمهٔ تسویه یک حوالهٔ دوطرفه میزند: پوز صفر میشود و همان مبلغ یکجا در حسابِ اصلی مینشیند. از این لحظه پرینتِ بانک و دفترِ شما دقیقاً میخوانند.
گزارشش کجاست
در گزارشها ← دفتر روزانه برچسبِ کارتخوان را بزنید: هر کارتکشی، هر بازگشت به کارت و هر تسویه، با فیلترِ دستگاه و بازهٔ تاریخ. سه عددِ بالای جدول جمعِ دریافتهای کارتی، تسویهشدهها و در انتظار تسویه را میگویند — همان عددی که هنوز به حسابِ اصلی نرسیده.
#«انتخاب ویژه» در دفتر روزانه (v40)
دفتر روزانه چهار برشِ آماده دارد که هر کدام جوابِ یک سؤالِ رایجاند:
| برچسب | چه چیزی را جدا میکند |
|---|---|
| حواله | هر حوالهای در بازه، دریافتی یا پرداختی — با امکانِ محدودکردن به یکی از دو جهت |
| کارتخوان | کارتکشی، بازگشت به کارت و تسویههای پوز، به تفکیکِ دستگاه |
| کسر و اضافه | ردیفهای کد ۸ (ریالی) و کد ۹ (طلا) — جمعشان جدا نگه داشته میشود چون واحدشان یکی نیست |
| پولی کردن ارز و سکه | جایی که سکه یا ارز به پول تبدیل شده: سکهای که قیمت خورده، یا ارزی که در همان سند ریال گرفته |
بازه را با میانبرهای امروز / ۷ روز / ۱ ماه / ۶ ماه / همه میبندید، و اگر خواستید تاریخِ دقیق بدهید گزینهٔ دستی دو کادرِ تاریخ باز میکند. بازهٔ فعال همیشه بالای پنل نوشته شده تا ندانسته گزارشِ نصفه نگیرید.
#کارت راهنمای گزارش حواله و کارتخوان — v97
پس از انتخاب برش، یک کارت راهنما در بالای دفتر توضیح میدهد که همان انتخاب چه چیزی را نشان میدهد. در برش حواله، دکمههای همه / دریافتی / پرداختی را بزنید؛ در برش کارتخوان، دستگاه و سپس همه / دریافت کارتی / تسویه را انتخاب کنید. سه عدد خلاصهٔ کارتخوان، دریافت، بازگشت و مبلغ در انتظار تسویه را از هم جدا میکنند.
این کارت فقط راهنمای دیداری است و هیچ دادهای ذخیره نمیکند. انتخاب برش، بازه و دستگاه با هم اعمال میشوند و گزارش همیشه بازهٔ فعال را بالای صفحه نشان میدهد؛ بنابراین برای بررسی ششماه گذشته، کافی است «۶ ماه» و دستگاه یا جهت موردنظر را انتخاب کنید.
#دفتر روزانهٔ خرید و فروش (v35)
«کارکرد معاملات» میگوید در کلِ دوره چقدر سود کردهاید. جدولِ زیرش همان عدد را روز به روز باز میکند — و این جدول را برای قاب گرفتنِ سود نمیخواهید، برای پیدا کردنِ اشتباه میخواهید.
هر سطر یک روز است، با این ستونها:
| ستون | یعنی |
|---|---|
| تاریخ | روزِ معامله — کلیککردنی |
| گرانترین فروش | بالاترین فیِ فروشِ همان روز |
| ارزانترین خرید | پایینترین فیِ خریدِ همان روز |
| وزن ۷۵۰ (یا تعداد) خرید / فروش | جمعِ چیزی که آن روز وارد و خارج شده |
| میانگین فیِ خرید / فروش | میانگینِ وزنی، نه میانگینِ ساده — چند خرید با مظنههای مختلف یک عدد میشوند |
| تراز روز | خرید منهای فروش. صفر باشد، آن روز ترازیدهاید |
| سود و زیان | نتیجهٔ همان روز نسبت به نرخ روز — کلیککردنی |
بالای جدول یک انتخاب هست: «فقط طلا» یا هر نوع سکهای که در آن دوره معامله کردهاید. برای سکه، واحدِ همهٔ ستونها بهجای وزن تعداد میشود و نرخِ سنجش، ارزشِ روزِ همان سکه است.
سطرِ آخرِ جدول جمعِ دوره است: گرانترین فروش و ارزانترین خریدِ کلِ دوره، جمعِ خرید و فروش، میانگینِ وزنیِ کل، و ترازِ نهایی — «۳۸ تا خریدم، ۳۰ تا فروختم، ۸ تا هنوز عقب هستم».
این عدد از کجا آمد؟
روی سودِ هر روز (یا سودِ جمعِ دوره) کلیک کنید تا فرمول با اعدادِ واقعیِ همان روز باز شود — نه شکلِ کلیِ فرمول، خودِ اعداد:
(میانگین فیِ فروش − نرخ روز) × جمع فروش = سود فروش
+
(نرخ روز − میانگین فیِ خرید) × جمع خرید = سود خرید
=
سود و زیانِ روز
اگر آن روز اجرت گرفته یا دادهاید، یک گامِ سومِ «اجرتِ دریافتی منهای پرداختی» هم اضافه میشود.
روزِ مشکوک، خودش را نشان میدهد
یک روز با ردیفِ قرمز علامت میخورد و زیرِ تاریخش دلیلش نوشته میشود، وقتی یکی از این دو اتفاق افتاده باشد:
- ردیفی بدون فی ثبت شده — سودِ آن روز ناقص حساب میشود.
- فیِ آن روز با میانهٔ فیِ کلِ دوره بیش از سه برابر فرق دارد — یعنی یک رقم اضافه یا جا افتاده است.
چرا این مهم است. فرض کنید فیِ فروش را ۸۱۸٬۴۰۰ زدهاید بهجای ۸۱٬۸۴۰٬۰۰۰. روی ۱۰۰ گرم، همین یک صفر، ۱٬۸۸۰٬۳۷۵٬۹۱۶ ریال زیانِ خیالی میسازد و سودِ کلِ ماه را بیمعنا میکند. تا وقتی سود فقط یک عددِ ماهانه باشد، این خطا هرگز دیده نمیشود و همانجا در دفتر میماند. بهمحضِ اینکه همان سود روزبهروز شکسته شود، خودش را لو میدهد.
از عدد تا سند، دو کلیک. روی سود کلیک کنید تا ببینید عدد از کجا آمده؛ اگر باز هم مشکوک بود، روی تاریخ کلیک کنید تا دفتر روزانه روی همان روز باز شود و ردیفِ خطادار را پیدا کنید. سند را که اصلاح کردید، به گزارشها برگردید — عدد درست میشود.
تضمینِ همخوانی: سودِ هر روز از همان تابعی میآید که «کارکرد معاملات» بهکار میبرد، پس جمعِ ستونِ سودِ این جدول همیشه با جمعِ کارکرد یکی است. اگر روزی این دو فرق کردند، یعنی باگ داریم — نه اینکه دو گزارش «دو جور حساب میکنند».
- بدهکاران و طلبکاران جاری، بهصورت خلاصهٔ موضوعی.
حواله و کارتخوان کجاست؟ اینها ردیفیاند نه تحلیلی؛ فهرست ردیفبهردیفشان را با «انتخاب ویژه» در بخش ۴۲ بگیر. گزارشها جمع و روند میدهد، دفتر روزانه تکتک سطرها را.
#۱۲.۴ مرکز افزونهها
از منوی مرکز افزونهها میتوانید امکانات تکمیلی پنل را یکجا ببینید، جستوجو کنید و وضعیت دسترسیشان را مدیریت کنید. بالای صفحه سه عدد همیشه مشخص است: افزونههای فعال، دورههای آزمایشی و افزونههای قابل فعالسازی.
#وضعیتها چه معنایی دارند؟
| وضعیت | معنی |
|---|---|
| فعال | دسترسی دائمی افزونه برای شما ثبت شده است |
| شامل بسته | افزونه از طریق بستهٔ دیگری فعال شده؛ مثلاً «آبشدهفروشی» امکانات «حساب سکه و ارز» را هم دارد |
| آزمایشی | دورهٔ ۳۰ روزه فعال است؛ تعداد روز باقیمانده روی کارت دیده میشود |
| در انتظار تأیید | درخواست خرید ثبت شده، اما هنوز فعالسازی دائمی تأیید نشده است |
| آزمایش پایان یافته | دورهٔ رایگان قبلاً استفاده شده و قابل تکرار نیست |
| بهزودی | افزونه هنوز آمادهٔ فعالسازی نیست |
برای پیدا کردن ابزار، نام یا کاربرد آن را در کادر جستوجو بنویسید یا فیلترهای همه / فعال / قابل فعالسازی را بزنید. با انتخاب هر کارت، امکانات، وضعیت، تاریخ پایان دوره و وابستگیهای بسته نمایش داده میشود.
#راهنمای انتخاب افزونه
پیش از کارتها، بخش کدام سطح برای کار شما مناسب است؟ کمک میکند بدون خرید تکراری مسیر درست را پیدا کنید. انتخاب این بخش فقط یک راهنمای زنده است و هیچ افزونه، خرید یا دسترسی را خودکار تغییر نمیدهد.
- نسخهٔ پایه: برای خرید و فروش معمول سکه و ارز کافی است و نیازی به افزونه ندارد.
- سکه و ارز: برای سکهفروش، صراف یا معاملهگری است که حساب تفصیلی، مانده و گزارش تخصصی میخواهد. اگر دورهٔ آزمایشی فعال باشد، دکمه مستقیماً مدیریت دوره و خرید را باز میکند.
- آبشدهفروشی: برای گردش وزنی، عیار، ذوب و تسویهٔ تخصصی است و حساب سکه و ارز را هم شامل میشود. اگر حساب سکه و ارز را قبلاً خریده باشید، همانجا مسیر ارتقا با مابهالتفاوت نشان داده میشود.
پیشنهاد، وضعیت واقعی حساب را هم در نظر میگیرد؛ بنابراین دسترسی فعال، افزونهٔ شامل بسته یا اعتبار خرید قبلی با متن روشن نمایش داده میشود. گزینهها با صفحهکلید قابل انتخاباند و نتیجهٔ تازه برای صفحهخوان اعلام میشود.
#آزمایش رایگان و خرید
- دکمهٔ شروع آزمایش ۳۰ روزه همان لحظه دوره را فعال میکند. هر افزونه فقط یک دورهٔ آزمایشی دارد و نوار پیشرفت، زمان مصرفشده و تعداد روز باقیمانده را نشان میدهد.
- در تمام مدت آزمایش و پس از پایان آن میتوانید ثبت درخواست خرید را بزنید. خرید تأییدشده دائمی است و نیازی به تهیهٔ دوباره ندارد.
- دکمهٔ ثبت درخواست خرید پرداخت یا دسترسی دائمیِ ساختگی ایجاد نمیکند؛ درخواست تا زمان تأیید در وضعیت «در انتظار تأیید» میماند.
- خرید و فروش سادهٔ سکه و ارز در نسخهٔ پایه باز است. افزونهٔ حساب سکه و ارز برای سکهفروشها، صرافیها و معاملهگرانی است که دفتر تفصیلی، مانده و گزارش تخصصی میخواهند.
- افزونهٔ آبشدهفروشی شامل امکانات حساب سکه و ارز است؛ لازم نیست هر دو را جداگانه تهیه کنید.
- اگر قبلاً «حساب سکه و ارز» را خریدهاید و بعداً «آبشدهفروشی» میخواهید، کارت آبشده گزینهٔ ارتقا با مابهالتفاوت را نشان میدهد. درخواست بهعنوان ارتقا ثبت میشود تا اعتبار خرید قبلی هنگام تأیید از مبلغ بسته کم شود.
- افزونهٔ بارکدِ خریداریشده با وضعیت فعال دائمی نشان داده میشود و نیازی به خرید دوباره ندارد.
#هماهنگکردن افزونه با شغل دفتر
بعد از فعالشدن یا شروع دورهٔ آزمایشیِ افزونهای که به نوع کسبوکار وابسته است، در پنجرهٔ جزئیات دکمهٔ فعالکردن برای این دفتر دیده میشود. برای نمونه، این دکمه در افزونهٔ آبشدهفروشی، شغل دفتر باز را روی آبشدهفروش میگذارد تا تنظیمات اولیه و گروههای کاری با کاربرد افزونه هماهنگ باشند.
این تغییر فقط روی دفتر باز انجام میشود. دفتر بایگانیشده فقط خواندنی است و شغل آن از مرکز افزونهها تغییر نمیکند. برای تغییر دستی نیز میتوانید به دفترهای حسابداری → تغییر شغل بروید.
نکتهٔ ایمنی: وضعیت افزونه با رنگ تنها بیان نمیشود؛ متن روشن «فعال»، «آزمایشی» یا «در انتظار تأیید» همیشه کنار آن وجود دارد. همهٔ دکمهها با صفحهکلید قابل دسترسیاند و در نمایش موبایل کارتها تکستونه میشوند.
#چاپ و رهگیری لیبل بارکد
پس از فعالبودن افزونهٔ بارکد، به کالا و انبار ← موجودی اجناس بروید. دکمهٔ مرکز چاپ لیبل بالای جدول، همهٔ لیبلها را باز میکند؛ آیکن بارکد روی هر ردیف نیز همان قلم را مستقیم انتخاب میکند.
- قلم موجودی را انتخاب کنید. بالای پنجره وزن موجودی، وزن لیبلهای فعال و وزن قابل چاپ را میبینید.
- وزن هر قطعه را از روی ترازو وارد کنید. وزن باید مثبت و حداکثر برابر ماندهٔ قابل چاپ همان قلم باشد؛ بنابراین مجموع لیبلهای فعال نمیتواند از وزن ردیف بیشتر شود.
- در صورت نیاز قیمت و یادداشت سفارش یا ویترین را بنویسید و چیدمان تکلیبل یا دو نسخه: کالا و صندوق را انتخاب کنید.
- ساخت و پیشنمایش را بزنید. سامانه یک شمارهٔ فرزند یکتا مانند
123456-001میسازد که به بارکد اصلی همان قلم متصل است. - از صف چاپ، یک لیبل یا همهٔ لیبلهای فعال را چاپ کنید. بارکد Code 128 داخل خود سامانه ساخته میشود و به سرویس بیرونی وابسته نیست.
اسکن در فروش: اسکنر USB مانند صفحهکلید کار میکند. در مرکز لیبل یا فرم ثبت سند، بارکد اصلی کالا یا شمارهٔ لیبل را اسکن و Enter بزنید؛ هر دو به همان قلم موجودی میرسند. شمارهٔ لیبل باعث ساخت قلم یا موجودی دوم نمیشود.
تعویض، ابطال و چاپ دوباره: برای لیبل آسیبدیدهای که هنوز فروخته نشده تعویض را بزنید تا نسخهٔ قبلی با وضعیت «تعویضشده» در سابقه بماند و یک شمارهٔ تازه ساخته شود. ابطال نیز رکورد را پاک نمیکند، اما وزنش را آزاد میکند. اگر فقط چاپ ناخواناست، چاپ دوباره همان شناسه را نگه میدارد؛ حتی سند فروش قبلی نیز از سابقهٔ لیبل قابل بازشدن است.
مرز حسابداری: ساخت، چاپ، تعویض یا ابطال لیبل هیچ سند مالی و هیچ تغییر مستقیمی در موجودی ایجاد نمیکند؛ لیبل فقط تخصیصِ قابل حسابرسی از وزن موجودی است. فروش واقعی همچنان با ثبت سند از موجودی کم میشود. در دفتر بایگانی، چاپ مجدد مجاز است اما ساخت، تعویض و ابطال غیرفعال میماند.
#فروش و مرجوعی با شناسهٔ لیبل
در ثبت سند میتوانید بارکد اصلی جنس یا شناسهٔ دقیق لیبل را دستی وارد یا با بارکدخوان اسکن کنید. اسکن لیبل، شناسه را روی ردیف سند نگه میدارد؛ تغییر وضعیت لیبل فقط وقتی انجام میشود که سند از کنترلها عبور کند و واقعاً ذخیره شود.
- از کنار کادر اسکن، هر لیبل یک ردیف یا تجمیع همنامها را انتخاب کنید. حالت تجمیع وزن و تعداد را جمع میکند، ولی شناسهٔ تکتک لیبلها زیر همان ردیف باقی میماند.
- بعد از ذخیرهٔ فروش، وضعیت لیبل فروختهشده و شمارهٔ سند فروش روی آن ثبت میشود. اسکن دوبارهٔ همان شناسه فروش دوم نمیسازد؛ خریدار، تاریخ و سند قبلی را نشان میدهد و دکمهٔ بازکردن سند فروش دارد.
- برای کالای برگشتی، در سندی که تشخیص مرجوعی دارد همان لیبل فروختهشده را اسکن کنید و افزودن مرجوعی را بزنید. ردیف با قیمتگذاری سند مبدأ ساخته و به همان فاکتور متصل میشود. پس از ذخیره، لیبل مرجوعشده و آمادهٔ فروش است.
- مرکز لیبل، شمار لیبلهای آماده و فروختهشده، سابقهٔ چاپ و سند فروش را یکجا نشان میدهد. بخش تطبیق لیبل و گردش موجودی برای حالتی است که کالا بدون اسکن لیبل فروخته شده: گردش همان قلم را باز کنید، سند خروج را پیدا کنید و پیش از چاپ شناسهٔ تازه، لیبل باقیمانده را تعیینتکلیف کنید.
نکتهٔ کنترلی: حذف لیبل از پیشنویس هیچ اثری ندارد. در ویرایش سند ذخیرهشده، وضعیتها دوباره از روی همهٔ اسناد بازسازی میشوند. سندی که یک لیبل را دوبار داشته باشد، لیبل باطل را مصرف کند یا مرجوعی را به فروش دیگری وصل کند ذخیره نمیشود.
#انبارگردانی بارکدی ویترین
در کالا و انبار ← موجودی اجناس ← مرکز چاپ لیبل دکمهٔ شمارش بارکدی ویترین را بزنید. میتوانید همهٔ لیبلهای آمادهٔ فروش یا فقط قلم انتخابشده را بشمارید. سامانه در لحظهٔ شروع، فهرست لیبلهای مورد انتظار را ثابت نگه میدارد تا تغییرهای بعدی نتیجهٔ همان شمارش را مخدوش نکند.
- همهٔ کالاهای ویترین، اطراف ترازو و محل بستهبندی را یکبار اسکن کنید. تعداد و وزن مورد انتظار، اسکنشده و باقیمانده همزمان بهروزرسانی میشوند.
- اگر یک لیبل دوباره خوانده شود، شمارنده افزایش نمییابد و پیام «قبلاً خوانده شده» نمایش داده میشود. لیبل فروختهشده، باطل، تعویضشده یا خارج از دامنه نیز وارد شمارش نمیشود.
- شمارش پس از هر اسکن خودکار ذخیره میشود. با ادامه در فرصت دیگر پنجره را ببندید؛ دفعهٔ بعد دکمهٔ ادامهٔ شمارش بارکدی همان نشست را باز میکند.
- لیبلهای خواندهنشده را ابتدا در ویترین و اطراف ترازو جستوجو کنید، سپس برای هرکدام یکی از نتیجههای واقعی را ثبت کنید:
- کالا هست؛ لیبل تعویض شود: لیبل خراب یا گمشده با سابقهٔ قبلی تعویض و شناسهٔ تازه آمادهٔ چاپ میشود.
- فروش بدون اسکن: شمارهٔ سند فروش قبلی را وارد کنید. اگر سند یک ردیف همنام و بدون شناسه داشته باشد، همان لیبل به ردیف متصل و فروختهشده میشود.
- کسری واقعی: پس از تأیید، لیبل باطل و وزن و تعداد قلم با یک سند رسمی اصلاح موجودی کم میشود؛ برای گمشدن یا سرقت واقعی از این گزینه استفاده کنید.
- وقتی همهٔ لیبلهای خواندهنشده اسکن یا تعیینتکلیف شدند، پایان شمارش را بزنید. نام کاربر، زمان پایان، تعداد اسکن و تعداد موارد تعیینتکلیفشده در سابقه میماند.
هشدار موجودی بدون لیبل یا اختلاف تعداد دفتر و لیبل فقط برای بررسی است و مانع اسکن نمیشود. وزن دفتر میتواند شامل کالای هنوز لیبلنخورده باشد. برای یافتن علت، از گردش همین قلم استفاده کنید و بدون دلیل واقعی لیبل تازه نسازید یا کسری ثبت نکنید.
#راهاندازی و اتصال بارکدخوان USB
برای اینکه اسکن در سند به محل فوکوس وابسته نباشد، ابتدا از تنظیمات ← بارکدخوان USB دکمهٔ راهاندازی بارکدخوان را بزنید. راهنما سه مرحله دارد:
- اسکنر را با USB به همان رایانه وصل کنید و یک لیبل چاپشده را در کادر آزمایش بخوانید. سامانه سرعت ورود و رسیدن Enter پایانی را بررسی میکند. اگر بارکدها در یک خط به هم میچسبند، در دفترچهٔ دستگاه بارکد تنظیم
Enter / CR suffixیاFactory defaultرا اسکن و آزمون را تکرار کنید. - بارکد اتصال نمایشدادهشده را با همان دستگاه اسکن کنید. این کد فقط مسیر ورودی اسکنر را فعال میکند و کالا، موجودی یا سند نمیسازد.
- یک بارکد اصلی یا لیبل فعال از موجودی اجناس را بخوانید. نام کالای تطبیقدادهشده باید در کارت نتیجه دیده شود؛ سپس پایان راهاندازی را بزنید.
پس از اتصال، در ثبت سند میتوانید بدون رفتن به کادر مخصوص بارکد، از هر کادر فرم کالایی را اسکن کنید. سامانه ورودی سریع اسکنر را از متن عادی جدا میکند، کد اسکنشده را از کادر جاری پاک میکند و همان قلم را به ردیف سند میافزاید. اگر کد در موجودی پیدا نشود، هیچ قلمی ساخته نمیشود و متن کاربر نیز بیدلیل جابهجا نمیشود.
کارت تنظیمات نام دستگاه، زمان آخرین اسکن و شمار اسکنهای موفق را نشان میدهد. بعد از جابهجایی کابل به پورت دیگر، تعویض رایانه یا بازگشت به تنظیمات کارخانه، اگر اسکن در سند شناخته نشد تست و مدیریت اتصال ← اتصال دوباره را اجرا کنید. قطع اتصال نیز فقط مسیر اسکن سریع را خاموش میکند؛ کالاها، لیبلها و اسناد حذف نمیشوند.
نکتهٔ سازگاری: بارکدخوان باید در حالت استاندارد USB HID Keyboard کار کند و پس از هر کد Enter بفرستد. هاب USB برقدار برای میزهایی که پورت کم یا اتصال ناپایدار دارند مناسبتر است؛ استفاده از هاب یا تغییر پورت، تعریف کالاها را تغییر نمیدهد.
#دستیار چرخهٔ سکه — v92
در ثبت سند دکمهٔ دستیار چرخهٔ سکه چهار سناریو را از هم جدا میکند: دریافت از کارگاه، فروش فیزیکی، فروش پولی و تسویه با تحویل سکه. راهنما برای هر سناریو نوع سند درست را نشان میدهد تا دریافت فیزیکی با خرید، یا تحویل سکه با پرداخت پولی اشتباه نشود.
- در دریافت از کارگاه، نوع سند دریافت است و مظنه لازم نیست؛ نوع سکه و تعداد واقعی را وارد کنید.
- در فروش فیزیکی، نوع سند فروش است و فی فروش برای محاسبهٔ ارزش وارد میشود.
- در فروش پولی، نوع سند فروش باقی میماند، اما یادداشت مشخص میکند سکه تحویل نشده و ماندهٔ سکه/ریال در حساب طرف ثبت شده است.
- در تسویه با تحویل سکه، نوع سند پرداخت است؛ سکهٔ واقعی از موجودی کم میشود و قیمتگذاری فروش وارد نمیشود.
- اجرت هر سکه در صورت نیاز جدا وارد میشود و بهصورت ردیف ریالی مستقل محاسبه میگردد. پیشنمایش قبل از ساخت سند، تعداد و ارزش را نشان میدهد.
#ثبت فروش و خرید پولی سکه و ارز — v91
در ثبت سند دکمهٔ معاملهٔ پولی سکه/ارز یک پیشنویس راهنماییشده میسازد. این مسیر برای معاملهای است که ماندهٔ سکه یا ارز در حساب طرف ثبت میشود، اما سکه یا ارز فیزیکی در همان لحظه از صندوق خارج یا وارد نمیشود.
- نوع فروش پولی یا خرید پولی، دارایی (سکه یا ارز) و طرف حساب را انتخاب کنید.
- نام نوع سکه یا ارز، تعداد/مقدار و فی یا نرخ هر واحد را وارد کنید. برای ارز، واحدی مانند دلار را جدا انتخاب کنید؛ نرخ واحد ارز را بزنید، نه اینکه مبلغ کل ریالی را به مقدار بسیار کوچک ارز تبدیل کنید.
- اگر تسویه انجام شده است، مبلغ دریافت/پرداخت ریالی را جداگانه وارد کنید و در صورت نیاز حساب بانکی را انتخاب کنید. این ردیف از مقدار سکه یا ارز مستقل است و سند نشان میدهد چه مقدار هنوز در حساب پولی باقی مانده است.
- ساخت پیشنویس سند را بزنید، ردیفها و جهت ورود/خروج را کنترل کنید و سپس از فرم سند، آن را ذخیره کنید.
این مسیر بهصورت پیشفرض با یادداشت «بدون جابهجایی فیزیکی» ساخته میشود. برای تحویل واقعی سکه یا ارز، از ردیف فیزیکی و سند دریافت/پرداخت متناسب با گردش واقعی استفاده کنید؛ مقدار ریالی را بهجای موجودی فیزیکی وارد نکنید.
#۱۲.۵ تسویه فردایی
معاملهای که امروز ثبت میشود ولی قرار است حساب آن در روز بعد قطعی شود، در صفحهٔ ثبت سند با گزینهٔ معامله فردایی / موعددار مشخص میشود. این علامت مبلغ تازهای نمیسازد؛ اثر همان سند را وارد چرخهٔ دفتر فردایی میکند.
#چرخهٔ سهمرحلهای مانده
صفحهٔ تسویه فردایی سه تب روشن دارد:
| مرحله | چه چیزی نمایش داده میشود؟ | اقدام بعدی |
|---|---|---|
| ۱. فرداییِ روز قبل | فقط معاملات فرداییِ پیش از امروز؛ معاملات تازهٔ امروز عمداً جدا میمانند | حسابهای کنترلشده را به «امروزی» منتقل کنید |
| ۲. امروزیِ آماده تسویه | حسابهایی که امروز از مرحلهٔ قبل آمدهاند | مظنهٔ قطعی را وارد و به «نقدی / حاضر» تبدیل کنید |
| ۳. تاریخچه تبدیل | نام شخص، شماره سند، مسیر تبدیل، زمان و کاربر ثبتکننده | برای حسابرسی و پیدا کردن اختلاف استفاده کنید |
این جداسازی مهم است: معاملهٔ فردایی که امروز تازه ثبت میکنید نباید با فرداییِ دیروز که آمادهٔ تعیینتکلیف است جمع شود. سیستم برای همین در مرحلهٔ اول فقط اسناد قبل از امروز را نشان میدهد.
#ابتدای روز: فردایی به امروزی
- تب فرداییِ روز قبل را باز کنید.
- در صورت نیاز گروه حساب را فیلتر کنید.
- اشخاص موردنظر را جداگانه انتخاب کنید یا انتخاب همه را بزنید. اگر با حسابی اختلاف دارید، آن را انتخاب نکنید تا همان فردایی بماند.
- شرح انتقال را کنترل و انتقال به امروزی را بزنید.
این مرحله هیچ وزن یا مبلغی را تغییر نمیدهد. فقط مرحلهٔ سند را عوض میکند و عبارت «فردایی به امروزی» را همراه شناسهٔ عملیات و کاربر ثبتکننده در سند نگه میدارد.
#پس از کنترل حساب: امروزی به نقدی
- وارد تب امروزیِ آماده تسویه شوید.
- حسابهای تأییدشده را انتخاب کنید.
- مظنهٔ فی تصفیه را وارد کنید؛ فی هر گرم ۱۸ خودکار محاسبه و در پیشنمایش دیده میشود.
- دکمهٔ فی تصفیه و انتقال به نقدی را بزنید.
در آموزشهای قدیمیتر این اقدام با عبارت «پولی شود» نمایش داده میشد. در رابط جدید، همان تبدیل با نام دقیقتر «فی تصفیه و انتقال به نقدی» انجام میشود و فقط پس از عبور حساب از مرحلهٔ «فرداییِ روز قبل» به «امروزیِ آماده تسویه» در دسترس است. این جداسازی جلوی مخلوطشدن معاملههای امروز با ماندههای روز قبل را میگیرد.
سیستم برای هر شخص یک سند حسابرسی میسازد: ماندهٔ طلای امروزی صفر و معادل آن به ماندهٔ پولی حاضر منتقل میشود. مظنه، فی هر گرم، وزن پیش از تسویه و شناسهٔ عملیات گروهی در سند باقی میمانند و ردیف با عنوان فی تصفیه قابل پیگیری است.
مرز مهم: این تبدیل پول را وارد صندوق جاری یا حساب بانکی نمیکند؛ فقط نوع ماندهٔ شخص را از طلا به پول تغییر میدهد. حساب انتخابنشده و معاملهٔ فرداییِ امروز نیز دستنخورده میمانند.
#پیدا کردن تبدیلها و گزارش روز
تب تاریخچه تبدیل بهصورت پیشفرض فقط عملیات امروز را نشان میدهد. سه شمارندهٔ بالای صفحه تعداد کل تبدیلهای امروز، «فردایی به امروزی» و «امروزی به نقدی» را جدا میکنند.
- با دکمههای امروز / همه تاریخ بازه را تغییر دهید.
- مسیر را روی همه مسیرها، فردایی به امروزی یا امروزی به نقدی بگذارید.
- در کادر جستوجو نام شخص، شماره سند، شرح یا نام کاربر ثبتکننده را بنویسید؛ نتیجه همزمان فیلتر میشود.
در هر یک از دو مرحلهٔ عملیاتی، نشان مقصد امن کنار راهنما دیده میشود. مقصد از روی مرحلهٔ فعال قفل است: فردایی فقط به امروزی و امروزی فقط به نقدی میرود. بنابراین برخلاف روشهای قدیمی نیازی به انتخاب دستی «ارز تبدیل» نیست و انتخاب اشتباهِ مقصد رخ نمیدهد.
برای جستوجوی سراسریتر، در دفتر روزانه عبارت «فردایی به امروزی» یا «امروزی به نقدی» را وارد کنید. چون مسیر تبدیل در توضیح خود سند ثبت میشود، تمام ردیفهای مرتبط با همان عبارت پیدا میشوند.
#پولی حواله (کد ۷)
در صفحهٔ ثبت سند، دکمهٔ پولی حواله · کد ۷ را بزنید. حسابی را که طلا از او خریدهاید و حسابی را که همان طلا به او حواله/فروخته میشود انتخاب کنید، سپس وزن، عیار و فی را یکبار وارد کنید.
با ثبت فرم، دو سند مرتبط ساخته میشود: خرید برای مبدأ و فروش برای مقصد. هر دو ردیف کد ۷ و یک شناسهٔ مشترک دارند؛ وزن، عیار، فی، تاریخ و شرح بین دو سمت قفل و همگاماند. بنابراین اصلاح فی از یک سمت، سمت دیگر را هم اصلاح میکند و دو رکورد از هم فاصله نمیگیرند. چون خرید و فروش همزمان و هممقدارند، صندوق جاری تغییری نمیکند.
دفتر بایگانیشده اجازهٔ تسویه یا ساخت پولی حواله نمیدهد.
#۱۲.۶ پنل تسویهٔ ریالی
صفحهٔ پنل تسویه ریالی برای هماهنگکردن واریزهاست: سمت راست طلبکارانی را میبینید که باید به آنها پرداخت شود و سمت دیگر بدهکارانی را که باید برای شما واریز کنند. گروه حساب، نام، کد یا تلفن را میتوانید فیلتر کنید تا حسابهای بانکی، هزینه، ذوب یا حسابهای داخلی وارد کار روزانه نشوند.
#پنل تسویهٔ ریالی و ماندهٔ خالص
کلید ماندهٔ خالص تعیین میکند ستونها با چه عددی مرتب شوند:
- در حالت خام، فقط ماندهٔ مستقیم ریالی دیده میشود.
- در حالت خالص، ماندهٔ ریال، طلای ۷۵۰، سکه و ارزِ دارای نرخ آنلاین به معادل ریالی روز تبدیل و با هم جمع میشوند.
- روی هر کارت، ریال مستقیم و جزئیات طلا و سکه جدا از عدد خالص باقی میماند؛ بنابراین عدد تبدیلشده جای اصل ماندهها را نمیگیرد.
پیش از گرفتن یا فرستادن شماره حساب، عدد خالص را کنترل کنید. مثلاً اگر ماندهٔ مستقیم شخص ۲۰ میلیارد ریال طلب است اما پس از محاسبهٔ طلای باز، خالص طلب او ۱۴ میلیارد ریال میشود، سامانه اجازه نمیدهد حساب مقصدی با مبلغ بیشتر از ۱۴ میلیارد ریال ثبت کنید.
#ثبت حساب مقصد، بدون ساخت سند
- در کارت طلبکار، حساب مقصد را بزنید.
- بانک، شماره حساب یا شبا، نام صاحب حساب، مبلغ و یادداشت (مانند «فوری») را وارد کنید.
- ثبت حساب مقصد را بزنید.
در این مرحله هیچ سند مالی ساخته نمیشود؛ فقط اطلاعات هماهنگی و سقف مبلغ ذخیره میشود. شماره حساب و ماندهٔ آن در پایین کارت شخص و در بخش حسابهای مقصد و وضعیت حواله قابل مشاهده است.
#ثبت واریز مرحلهای
وقتی فیش یا تأیید واریز رسید، از ردیف حساب مقصد ثبت واریز را بزنید، بدهکارِ واریزکننده و مبلغ تأییدشده را انتخاب کنید. برای هر فیش، بانک مبدأ، شماره پیگیری، ساعت واریز و یادداشت اختیاری را نیز جدا وارد کنید. سقف امن هر واریز، کمترِ این دو عدد است:
- مبلغ باقیماندهٔ حساب مقصد؛
- بدهی خالص واریزکننده.
با تأیید، دو سند مرتبط و قفلشده ساخته میشود تا ماندهٔ طلبکار و بدهکار همزمان اصلاح شود. اگر مبلغ در چند نوبت یا توسط چند بدهکار پرداخت شود، هر فیش جدا ثبت و مانده خودکار کم میشود. فهرست فیشها زیر همان حساب مقصد، نام واریزکننده، مبلغ، بانک، پیگیری و ساعت هر نوبت را نشان میدهد. با رسیدن جمع واریزها به مبلغ درخواست، ردیف سبز و عبارت کامل حواله شد نمایش داده میشود.
هر فیش تأییدشده remitId مستقل خود را دارد و مشخصات آن روی هر دو سند آینه ذخیره میشود؛ پس تغییر یک حواله، حوالههای دیگرِ همان حساب مقصد را دستکاری نمیکند. در حوالهٔ طلای فیزیکی نیز همان جفت سند ساخته میشود، اما ردیف طلا فی ندارد و بدهی ریالی یا سود و زیان ساختگی ایجاد نمیکند.
اگر از انجام حواله مطمئن هستید ولی فیش هنوز در دسترس نیست، میتوانید ردیف ناقص را دستی کامل حواله شد علامت بزنید. این علامت فقط کار پیگیری را میبندد و برای مبلغ باقیمانده سند مالی نمیسازد؛ هر زمان لازم بود با بازگشایی آن را به صف پیگیری برگردانید.
مرز ایمنی: حساب مقصدی که حتی یک واریز مرتبط دارد مستقیم حذف نمیشود. ابتدا باید اسناد مرتبط را بررسی و حذف کنید تا سابقهٔ مالی بیصاحب نماند. در دفتر بایگانیشده نیز پنل فقط برای مشاهده است و ثبت، تکمیل یا حذف انجام نمیشود.
#۱۲.۷ دفترهای حسابداری و بستن سال مالی
هر سالِ مالی یک دفتر است. آخرِ سال دفتر را میبندید: ماندهها و موجودیها به یک دفترِ تازه میروند و دفترِ قبلی بایگانی و قفل میشود — همیشه میتوانید ببینیدش، ولی دیگر تغییرش نمیدهید.
چرا اصلاً میبندید؟ چون تعدادِ اسنادِ یک سال از حد میگذرد، شمارهٔ فاکتور باید از اول شروع شود، و گزارشها باید امسال را نشان بدهند نه ده سالِ روی هم.
#بستن سال، قدم به قدم
از منو به دفترهای حسابداری بروید و «بستن سال مالی» را بزنید. پنجرهٔ بستن سال سه مرحله دارد و تا بازبینی نهایی هیچ تغییری در دفتر نمیدهد.
۱) آمادهسازی و پشتیبان. ابتدا یک پشتیبان کامل دانلود کنید؛ این فایل دادهها، عکسها و پیوستها را با هم نگه میدارد. فایل را در محلی جدا ذخیره و سپس نگهداری آن را تأیید کنید.
| مورد | رفتار سیستم | کار درست |
|---|---|---|
| آبشدهٔ شرطی تعیینتکلیفنشده | مانع بستن سال است؛ مانده هنوز قطعی نیست | ابتدا جواب عیار/تسویه را ثبت کنید |
| قسط سررسیدگذشته | هشدار پیشنهادی؛ قسط ناتمام منتقل میشود | در صورت امکان وصول یا تمدید کنید |
| چک سررسیدگذشتهٔ باز | هشدار پیشنهادی؛ چک با صاحبش منتقل میشود | پاس، برگشت یا تمدید را ثبت کنید |
| کار باز تعمیر | هشدار پیشنهادی؛ امانت با سندش منتقل میشود | موجودی نزد تعمیرکار را کنترل کنید |
۲) تنظیم انتقال. نام دفتر جدید و سه حداقل انتقال را مشخص کنید:
- موجودی انبار کمتر از ۰٫۳ گرم
- مانده طلای کمتر از ۰٫۳ گرم
- مانده ریالی کمتر از ۹۹۹٬۹۹۹ ﷼
این عددها برای اختلاف ترازو و خردهماندهها هستند. صفر بگذارید تا هیچ خردهماندهای حذف نشود. پیشنمایش زنده نشان میدهد چه چیزهایی منتقل میشوند و چه مقدار بهخاطر آستانهها کنار میماند.
۳) بازبینی و تأیید. نام دفتر مبدأ و مقصد و دو ستون «منتقل میشود / منتقل نمیشود» را بخوانید. پس از تأیید صریح، عملیات اجرا و دکمه تا پایان غیرفعال میشود.
اصل ایمنی: اگر ذخیرهٔ بایگانی روی سرور ناموفق شود، عملیات متوقف میشود و دفتر فعلی دستنخورده میماند.
#چه چیزی منتقل میشود
| میآید | نمیآید |
|---|---|
| ماندهٔ همهٔ طرف حسابها (طلا، ریال، سکه، ارز) | اسنادِ بستهشدهٔ سال |
| چکِ باز، با صاحبش | چکِ پاس/نقد/خرجشده |
| قسطِ ناتمام و پرداختهای قبلیاش | تاریخچهٔ کارها |
| جنسی که نزد تعمیرکار است | هزینههای سال |
| موجودی انبار و آبشده | — |
| ماندهٔ صندوق و حسابهای بانکی | — |
| اشخاص، کالاها، تنظیمات و حسابدارها | — |
چکِ برگشتیِ سالِ قبل، بدون دردسر. در خیلی از نرمافزارها چکی که از سالِ قبل منتقل شده زیر یک حسابِ داخلی به نامِ «موجودی ابتدای دوره» میرود و نامِ صاحبش فقط در یادداشت میماند — نتیجه اینکه وقتی چک برگشت میخورَد، در فهرستِ چکهای آن شخص پیدایش نمیکنید و مجبورید دور بزنید. اینجا اینطور نیست: چکِ باز با سندِ خودِ همان شخص منتقل میشود. پس در دفتر جدید هم صاحبش را دارد و «برگرداندن چک» مثل هر چکِ دیگری کار میکند.
سنِ حساب گم نمیشود. ماندهٔ منتقلشده با تاریخِ رأس ثبت میشود، نه با تاریخِ امروز. یعنی طلبِ قدیمی در دفتر جدید هم قدیمی میمانَد و راسگیری و گزارشِ سنِ بدهی درست میماند.
سودِ پارسال در امسال شمرده نمیشود. سندهای منتقلشده فقط مانده میسازند؛ در «کارکرد معاملات» و «دفتر روزانهٔ سود» وارد نمیشوند، چون معاملهٔ آنها پارسال انجام شده و سودش همانجا حساب شده است.
#تماشای دفترهای گذشته
در جدولِ دفترهای حسابداری همهٔ دفترها با تاریخِ گشایش، تاریخِ بستهشدن و تعدادِ سند و طرف حساب فهرستاند. دفترِ جاری با نشانِ سبز مشخص است.
روی «تماشا» بزنید تا یک دفترِ بایگانی باز شود. آن وقت یک نوارِ طلایی بالای صفحه میآید: «این دفتر بایگانی است». همهٔ گزارشها، چاپ، PDF و Excel در دسترساند، ولی هیچ تغییری ذخیره نمیشود. با دکمهٔ «بازگشت به دفتر جاری» برگردید.
#اصلاح بعد از بستن سال
اگر ماندهای اشتباه منتقل شده، دفتر قدیمی را ویرایش نکنید؛ در دفتر جدید برای همان شخص سند اصلاح مانده ثبت کنید. اگر کل عملیات اشتباه بوده و هنوز در دفتر جدید کاری نکردهاید، فایل پشتیبانی را که پیش از بستن گرفتهاید از تنظیمات بازگردانی کنید. حذف دستی دفتر جدید و بازکردن قفل دفتر قدیمی جای بازگردانی پشتیبان را نمیگیرد.
ورود کاربران سراسری است و بعد از بستن سال رمز جدا لازم ندارند؛ دسترسی حسابدارها همراه دفتر جدید میآید و در اتاق فرمان قابل بازبینی است. برای کمکردن حجم پشتیبانها، دفتر خیلی قدیمی را فقط پس از نگهداری یک پشتیبان کامل در دو محل حذف کنید؛ اگر فقط نباید در سوئیچر دیده شود، ستون نمایش را خاموش کنید.
#۱۲.۶ دفترهای من: چند دفتر در کنار هم
بستنِ سال یک دفتر را جای دفترِ قبلی میگذارد. ولی گاهی چند دفترِ همزمان میخواهید:
- تا حالا داشتید نرمافزار را امتحان میکردید و همهٔ ورودیها تستی بوده؛ حالا میخواهید دفترِ واقعی را شروع کنید.
- چند مغازه دارید و حسابکتابِ هرکدام از دیگری جداست.
- میخواهید یک دفترِ آزمایشی داشته باشید که هر وقت خواستید چیزی را در آن امتحان کنید، بدون ترس از خرابشدنِ دفترِ اصلی.
در تعدادِ دفترها هیچ محدودیتی ندارید.
#ساختِ دفتر جدید
از منو به دفترهای حسابداری → لیست دفترها بروید و دکمهٔ سبزِ + را بزنید. سه چیز میپرسد:
۱) نامِ دفتر. هر چه دوست دارید — «گالری کیمیا»، «شعبهٔ دو»، «دفتر ۱۴۰۵».
۲) شغل شما؟ تکفروش، بنکدار، آبشدهفروش، سازنده، سکهفروش یا تعمیرکار. این فقط یک برچسب نیست: بر اساسِ شغلی که انتخاب میکنید، گروههای طرف حساب و دسترسیهای اولیه خودشان ساخته میشوند تا مجبور نباشید از صفر تعریفشان کنید. بعداً هم قابلِ تغییر است.
۳) دفترِ پیشفرض باشد؟ یعنی هر بار که وارد برنامه میشوید، همین دفتر باز شود.
نامِ تکراری قبول نمیشود. اگر نامی بزنید که قبلاً هست، همانجا زیرِ کادر مینویسد: مشابه همین در سیستم موجود است — نامِ دیگری بگذارید یا اول نامِ دفترِ قبلی را عوض کنید. کارِ متداول همین دومی است: میخواهید دفترِ واقعیتان دقیقاً اسمِ «گالری کیمیا» را داشته باشد، ولی دفترِ تستی همین اسم را گرفته. اول نامِ دفترِ تستی را به «گالری کیمیا تستی» تغییر بدهید (از همان جدول، دکمهٔ ویرایش)، بعد دفترِ جدید را با نامِ دلخواهتان بسازید.
#دفترِ جدید کاملاً خالی است
این مهمترین نکتهٔ این بخش است: راهی برای انتقالِ اشخاص، اجناس یا حسابها بین دو دفتر وجود ندارد — نه اینکه هنوز ساخته نشده باشد؛ اصلاً چنین چیزی نیست و دنبالش نگردید. حسابهای دفترِ جدید از دفترِ قبلی کاملاً جدا هستند.
پس اگر تا حالا اطلاعاتِ زیادی وارد کردهاید و فقط چون «تستی» بوده میخواهید از نو شروع کنید، دو راهِ بهتر دارید:
۱. همان دفتر را نگه دارید. کلمهٔ «تستی» را از نامش بردارید و فقط ورودیهای اشتباه را اصلاح کنید. اشخاص و اجناسی که وارد کردهاید سرِ جایشان میمانند.
۲. اگر چند مورد جا افتاده یا غلط است، از بخشهای اصلاحِ همین راهنما استفاده کنید (اصلاح موجودی، ویرایشِ ماندهٔ اول دوره در فرمِ شخص، و ویرایشِ سند).
دفترِ نو را وقتی بسازید که واقعاً میخواهید از صفر شروع کنید — نه برای اینکه چند ردیف را درست کنید.
#جابهجایی بین دفترها
بالای صفحه، کنارِ دکمهٔ روز/شب، نامِ دفترِ باز نوشته شده. رویش کلیک کنید تا فهرستِ همهٔ دفترها باز شود:
- کادرِ جستوجو برای وقتی که دفترها زیاد شدهاند
- دو سربرگِ جاری و مخفی
- هر دفتر یک کارت است با کد، نام، شغل و تاریخِ گشایش؛ دفترِ باز نشانِ سبز دارد
روی هر کارتی بزنید، همان لحظه واردِ آن دفتر میشوید. هر وقت خواستید برگردید — مثلاً میخواهید در دفترِ تستی چیزی را امتحان کنید — دوباره کلیک و برگردید. کارِ ذخیرهنشدهای گم نمیشود: پیش از سوئیچ، دفترِ فعلی کامل ذخیره میشود.
اگر یک دفترِ بایگانی را برای تماشا باز کرده باشید، تا وقتی به دفترِ جاری برنگشتهاید نمیتوانید سوئیچ کنید یا دفترِ تازه بسازید. این عمدی است و از دفترِ زندهٔ شما محافظت میکند.
#جدولِ لیست دفترها
| ستون | یعنی |
|---|---|
| کد | شمارهٔ کوتاهِ دفتر؛ در گفتوگو با پشتیبانی بهکار میآید |
| دفتر حسابداری | نامِ دفتر |
| شغل شما؟ | شغلی که موقعِ ساخت انتخاب کردید |
| تاریخ گشایش | روزِ ساختِ دفتر |
| سند / طرف حساب | حجمِ کارِ داخلِ دفتر |
| وضعیت | جاری یا بایگانیشده |
| دفتر پیشفرض | دفتری که برنامه با آن بالا میآید (فقط یکی) |
| نمایش | خاموشش کنید تا به سربرگِ «مخفی» برود — حذف نمیشود |
| ID | شناسهٔ کاملِ دفتر؛ موقعِ پشتیبانی لازم میشود |
از همین جدول میتوانید دفتر را باز کنید، نامش را عوض کنید یا حذفش کنید.
حذف برگشتناپذیر است و همهٔ اسناد و اطلاعاتِ آن دفتر را میبَرد. برای اطمینان باید نامِ دفتر را دقیقاً تایپ کنید. دفتری که همین حالا باز است حذف نمیشود — اول به دفترِ دیگری بروید.
#راهاندازیِ گامبهگام دفترِ نو
وقتی دفترِ تازهای را باز میکنید، صفحهٔ راهاندازی میآید — انگار تازه برنامه را تحویل گرفتهاید و میخواهید شروع به کار کنید. پنج گام دارد:
شروع → شغل شما؟ → موجودی ابتدای دوره → حسابها → کاربران
هر گام شما را به همان صفحهٔ اصلیِ برنامه میبَرد، نه به یک فرمِ کوچکِ جداگانه؛ یعنی همهٔ فیلدها را در اختیار دارید و بعداً هم از همانجا ویرایش میکنید.
- موجودی ابتدای دوره چهار قسمت دارد: موجودی نقدی و ارزی، سکه، آبشده و متفرقه، و اجناسِ ویترین.
- حسابها: حسابِ بانکی و صندوق، طرف حسابها با ماندهٔ اول دوره، و چکهای ابتدای دوره.
- کاربران: حسابدارها و دسترسیهایشان.
نوارِ پیشرفتِ بالای صفحه خودش میفهمد چه کاری انجام شده — از روی دادهٔ واقعی، نه از روی تیک زدنِ شما. اگر ردیفی را پاک کنید، آن گام دوباره ناتمام میشود.
هر گامی که به شما مربوط نیست، دکمهٔ «فعلاً نه» دارد: «اگر الآن هیچی موجود ندارید، این مرحله را بیخیال شوید.» هر وقت خواستید از منو به همین صفحه برگردید.
امروز را مبنا بگذارید. لازم نیست تاریخِ افتتاحِ مغازه یا اولِ سال را بنویسید و بروید عقب. هر چه امروز در مغازه دارید — نقد، طلا، سکه، طلبِ مردم و بدهیِ شما — همان را وارد کنید. از فردا برنامه خودش حساب را نگه میدارد.
وقتی گامها تمام شد، دکمهٔ «پایان راهاندازی» ابتدا یک پنجرهٔ تأیید نهایی باز میکند. در این پنجره تعداد مراحل، حسابهای دارای مانده و دو جزء مبنای افتتاحیه را میبینید:
- مبنای طلایی بر حسب گرم ۷۵۰؛
- مبنای ریالی برای نقد، بانک، چک، ارزِ ارزشگذاریشده و اقلام مبلغی.
با تأیید، سامانه یک حساب سیستمی به نام «تراز افتتاحیه دفتر» با ماهیت سرمایه و برداشت میسازد. این حساب طرفِ مقابلِ موجودیها و ماندههای روز شروع است؛ چیزی را پاک یا جابهجا نمیکند، اما باعث میشود خلاصه وضعیت در لحظهٔ شروع صفر باشد و از آن پس فقط نتیجهٔ کارهای جدید — سود، زیان، هزینه و برداشت — روی عدد کل اثر بگذارد.
طلا و ریال عمداً جدا ثبت میشوند. اگر کل افتتاحیه با نرخ امروز به یک مبلغ ریالی تبدیل میشد، تغییر مظنه در روز بعد بهاشتباه سود یا زیان میساخت. بخش طلایی با وزن ۷۵۰ نگهداری میشود تا تغییر قیمت، مبنای شروع را خراب نکند.
بعد از تأیید مستقیماً وارد خلاصه وضعیت میشوید. یک نوار سبز بالای گزارش، مبنای ثبتشده را نشان میدهد. پایان راهاندازی دوباره اجرا نمیشود؛ اگر موجودی یا ماندهای اشتباه است، همان مورد را از صفحهٔ موجودی، حساب بانکی یا طرفحساب ویرایش کنید.
#خواندن خلاصه وضعیت پس از راهاندازی
فرمول عدد کل ساده است:
طلب مغازه − بدهی مغازه + موجودی فیزیکی
ماندهها ابتدا به تفکیک ماهیت — بنکداری، تکفروشی، بانک، امانات، سرمایه و برداشت و مانند آن — در کارتهای جدا دیده میشوند. روی هر کارت بزنید تا حسابهای سازندهٔ همان عدد باز شوند؛ روی نام یک طرفحساب هم بزنید تا دفتر معین و منشأ ردیفها را ببینید. این تعامل تککلیک و قابلاستفاده با صفحهکلید است و جای دوبارکلیکِ رابطهای قدیمی را میگیرد.
فروش یا هر سند تازه بلافاصله سه بخش را تغییر میدهد: موجودی فیزیکی، ماندهٔ طرفحساب و عدد کل وضعیت. به این ترتیب میتوانید ببینید چه مقدار طلا از ویترین کم شده، چه مبلغی جای آن آمده و سود یا زیان خالص بر حسب ریال و گرم ۷۵۰ چقدر است.
#۱۳. اتاق فرمان و دسترسیها
فقط مدیر به این صفحه دسترسی دارد. حسابدار بازش کند، پیغامِ «فقط مدیر دسترسی دارد» میبیند.
اتاق فرمان دو سربرگ دارد: حسابدارها و دسترسیها و رویدادها و فعالیتها.
#حسابدارها و دسترسیها
- هر حسابدار نام، نام کاربری، رمز عبور و نقش دارد. نقش یا مدیر است یا حسابدار.
- مدیر به همهٔ صفحهها و به خودِ اتاق فرمان دسترسی دارد. برای حسابدار، صفحههای مجاز را یکییکی تیک میزنی؛ صفحههای تیکنخورده اصلاً در منوی او دیده نمیشوند.
- تا وقتی هیچ کاربری نساختهای، سیستم بدون ورود باز میشود. با ساختنِ اولین کاربر، صفحهٔ ورود فعال میشود — پس اولین کاربر را حتماً با نقشِ مدیر بساز، وگرنه دیگر به اتاق فرمان نمیرسی.
- کاربر را میشود غیرفعال کرد بهجای حذف. غیرفعال نمیتواند وارد شود ولی کارهای ثبتشدهاش سرِ جایشان میمانند.
- ورود در همان سربرگِ مرورگر میماند (session)؛ بستنِ مرورگر یعنی ورودِ دوباره.
#رویدادها و فعالیتها
این سربرگ فهرستِ سادهٔ آخرین کارهاست: چه کسی، کِی، چه کرد. برای نگاهِ سریع خوب است، ولی جستوجو، فیلتر، مقدارِ قبلی/جدید و عکسِ حذفشدهها را ندارد.
برای همهٔ آنها صفحهٔ تاریخچه کارها (§۴۳) هست — همان داده، ولی ردیفبهردیف و با جزئیاتِ تغییر. دکمهٔ رفتن به آن، بالای همین سربرگ است.
هشدار دربارهٔ «پاکسازی رویدادها»: این دکمه تاریخچه کارها را هم خالی میکند. بعد از آن دیگر معلوم نیست چه کسی چه چیزی را عوض کرده؛ برگشتی هم ندارد. پیش از زدنش، اگر لازم است، از تاریخچه خروجی CSV بگیر.
#۱۴. تنظیمات
- نام فروشگاه، مظنه مثقال، عیار مبنا، درصد پیشفرض سود فروشنده و مالیات.
- تخفیف مبلغ از راست (رقم) — چند رقم از سمت راستِ مانده با دکمهٔ «بخشیدن خرده» صفر شود. پیشفرض ۴؛ کنارش حداکثرِ مبلغِ بخشیدنی نشان داده میشود. جزئیات در کسر و اضافه.
- خروجی پشتیبان JSON و پاکسازی کامل دادهها.
- گروههای اشخاص و مجوز عملیات (دریافت/پرداخت/خرید/فروش/مرجوعی) روی انواع قلم.
#۱۵. عیار تهحساب: تسویهٔ طلا با عیار توافقی
گاهی با یک طرفحساب توافق میکنی که ماندهی طلایش را موقع تسویه با یک عیار مشخص (مثلاً ۷۴۰) حساب کنید، نه با عیار مبنای ۷۵۰. برای این کار هر شخص یک فیلد «عیار تهحساب» دارد.
#کجاست
در فرم شخص (ساخت/ویرایش)، کنار «سقف اعتبار» و «مهلت تسویه»، فیلد «عیار تهحساب». خالی بگذاری = بدون تبدیل (همان ۷۵۰). اگر پُرش کنی (مثلاً ۷۴۰)، ماندهی طلای این شخص هنگام تسویه به همان عیار نشان داده میشود.
#چطور کار میکند
ماندهی طلا همیشه در معادل ۷۵۰ نگهداری میشود (هیچ عددِ مالیای عوض نمیشود). «عیار تهحساب» فقط یک نمایشِ تبدیلشده اضافه میکند:
وزن به عیار توافقی = وزن۷۵۰ × ۷۵۰ ÷ عیار تهحساب
مثال: مشتری ۷٫۴ گرم معادل ۷۵۰ طلب دارد و عیار تهحسابش ۷۴۰ است → ۷٫۴ × ۷۵۰ ÷ ۷۴۰ = ۷٫۵ گرم به عیار ۷۴۰. یعنی موقع تسویه بهجای ۷٫۴ گرمِ ۷۵۰، معادلِ ۷٫۵ گرمِ ۷۴۰ تحویل میگیرد/میدهد.
#کجا دیده میشود
- کارت شخص: زیر «مانده طلا» یک خط طلایی: «= ۷٫۵ گرم به عیار ۷۴۰»؛ و یک چیپ «عیار تهحساب» بالای کارت.
- فاکتور چاپی: در سطرهای «مانده قبلی» و «مانده نهایی»، طلا به عیار توافقی نوشته میشود.
این قابلیت فقط نمایشی/تسویهای است؛ روی جمع سند و محاسبات سود اثری ندارد. اشخاص بدون «عیار تهحساب» دقیقاً مثل قبل کار میکنند.
#۱۶. گروههای دسترسی اشخاص و هشدار عملیات
این قابلیت جلوی ثبت اشتباهِ سند را میگیرد: برای هر گروه از اشخاص مشخص میکنی چه عملیاتی «مجاز» است، و اگر سندی خلاف آن ثبت شود، هنگام ذخیره هشدار میگیری (نه ممانعت).
#ساخت گروه
از تنظیمات ← «گروههای اشخاص و دسترسیها» ← + گروه جدید. برای هر گروه:
- نام (مثلاً بنکدار، سازنده، مشتری).
- قالب آماده: به انتخاب خودم، آبشدهفروش، کیفی، مشتری، سازنده — نقطهٔ شروع سریع.
- ماتریس مجوز: جدولی از ۶ عملیات × ۹ نوع قلم. عملیاتها: دریافت، پرداخت، خرید، فروش، دریافت مرجوعی، پرداخت مرجوعی. قلمها: آبشده، متفرقه، نقدی/پولی، چک، ساخته، کالای غیرطلایی، خدمات، نیمساخته، ارز و سکه. هر خانه را میتوانی تیک بزنی یا برداری.
#اتصال به شخص
در فرم هر شخص، فیلد «گروه دسترسی» را روی گروه دلخواه بگذار. گروهِ «به انتخاب خودم» = همهچیز مجاز = بدون هشدار.
#هشدار هنگام ثبت
موقع ذخیرهٔ سند، سامانه ردیفها را با مجوزِ گروهِ طرفحساب میسنجد:
- نوعِ قلمِ هر ردیف از روی نوع ردیف و کد شرح تشخیص داده میشود (طلا با شرحِ «۱ آبشده»→آبشده، «۲ متفرقه»→متفرقه، وگرنه ساخته؛ ریالی با شرحِ «۶ چک»→چک، وگرنه نقدی).
- ردیفهای با تشخیص مرجوع با عملیاتِ «دریافت/پرداخت مرجوعی» سنجیده میشوند.
- اگر عملیاتی خارج از مجوز باشد، مودالِ هشدار باز میشود؛ میتوانی «با این حال ثبت شود» را بزنی.
مثال (سبک کیمیا): برای گروه «سازنده» دریافتِ آبشدهٔ خالی را غیرمجاز کن (چون به سازنده آبشده میدهی، نه از او میگیری) ولی «دریافت مرجوعی آبشده» را مجاز بگذار. حالا اگر در سند دریافت از سازنده یک ردیف آبشده بزنی، هشدار میگیری: «گروه «سازنده» اجازهٔ (دریافت آبشده) را ندارد.»
#۱۷. عکس اجناس
برای جلوگیری از اشتباه در فروش، میتوانی به هر کالا عکس بدهی تا در لیست و روی فاکتور دیده شود.
#دو راه افزودن عکس
- روی نوع کالا (اطلاعات پایهٔ جنس): موقع تعریف/ویرایش «جنس»، بخش «عکس کالا» را داری؛ عکس را انتخاب کن. این عکس روی همهٔ اجناسِ آن نوع مینشیند.
- روی یک ردیفِ خاصِ موجودی: در کالا و انبار ← موجودی اجناس، کنار نام هر ردیف دکمهٔ عکس (آیکن تصویر) هست؛ میتوانی عکس اختصاصیِ همان ردیف را بگذاری. اگر ردیف عکس اختصاصی نداشته باشد، خودکار از عکس نوعِ کالا استفاده میشود.
#کجا دیده میشود
- موجودی اجناس: بندانگشتیِ عکس کنار نام هر ردیف.
- ثبت سند: هنگام تایپ نام کالا در ردیف طلا، بندانگشتی نشان داده میشود تا فروشنده اشتباه نکند.
- فاکتور چاپی: عکس کالا کنار شرح هر ردیف چاپ میشود.
#نکتهٔ مهم دربارهٔ ذخیرهسازی
عکسها روی سرور ذخیره میشوند و فقط نشانیشان در داده نگهداری میشود (نه خودِ عکس داخل داده، تا حجم بالا نرود). حداکثر اندازهٔ هر عکس ۱٫۵ مگابایت و فرمتهای مجاز JPG/PNG/WEBP/GIF است. چون عکسها روی همان سرور میمانند، برای احتیاط از سرور پشتیبان بگیر.
#سازندهٔ جنس (تعریف اجناس)
عکسِ کالا از دلِ همان فرمی میآید که کالا را میسازد. صفحهٔ «اجناس» فهرست همهٔ کالاهای تعریفشده است و با دکمهٔ «جدید» فرم تعریف جنس باز میشود.
- نوع کالا را اول انتخاب کن، چون بقیهٔ فیلدها بر اساس آن تنظیم میشوند: ساخته، کالای غیر طلایی، خدمات، ارز، سکه.
- فیلدهای اصلی فرم: نام و عکس، گروه جنس، عیار (مثلاً ۷۵۰)، محاسبهٔ فی (وزنی/عددی)، ارز دریافتی، پلاستیک (دارد/ندارد)، سنگ (دارد/ندارد)، ارزش افزوده (دارد/ندارد)، سازنده، فی فروش نقدی و درصد فروش نقدی.
- فهرست اجناس ستونهای عکس، کد، نام، عیار، وزن یکعدد، سازنده، فی دریافتی، فی فروش نقدی، گروه جنس، وضعیت نمایش و یادداشت را دارد و با سربرگهای ساخته/کالای غیر طلایی/خدمات/ارز و سکه/گروه جنس فیلتر میشود.
- ویرایش: جنس را انتخاب و دکمهٔ «ویرایش» را بزن؛ همان فرم با مقادیر فعلی باز میشود. تغییر وضعیت نمایش، جنس را از فهرست انتخابِ سند پنهان میکند بدون آنکه حذف شود.
#۱۸. دفتر ذوب و آبشده
طلای متفرقه (شکسته، دستدوم، خردهریز) قیمت مشخصی ندارد تا وقتی آب شود و عیار واقعیاش معلوم گردد. صفحهٔ «ذوب و آبشده» همین چرخه را از لحظهٔ تحویل به ریگیری تا برگشت آبشده دنبال میکند.
#چرخهٔ کار
- قبض ذوب میزنی: متفرقهها را به ذوبخانه/ریگیری تحویل میدهی و اقلام را با وزن و عیارِ تخمینی ثبت میکنی. قبض در وضعیت «در ذوب» میماند.
- آبشده برمیگردد: با دکمهٔ «ثبت ری» وزن آبشده و ری (عیار واقعیِ اعلامشده) را وارد میکنی. قبض «برگشته» میشود.
- اختلاف حساب میشود: ورودی و خروجی هر دو به وزن معادل ۷۵۰ تبدیل و مقایسه میشوند.
#افت و سرک
- افت (کسری): خروجی کمتر از ورودی — طبیعی است، چون عیارِ تخمینیِ متفرقه معمولاً از عیار واقعی بالاتر زده میشود و مقداری هم در ذوب از بین میرود.
- سرک: خروجی بیشتر از ورودی — یعنی جنس از تخمینت بهتر درآمده.
هنگام ثبت ری، درصد اختلاف زنده نشان داده میشود و اگر از ۳٪ بگذرد هشدار قرمز میگیری. این هشدار جلوی اشتباهِ رایج را میگیرد: جابهجا وارد کردن وزن و عیار، یا افتادن یک رقم.
مثال: ۱۰ گرم عیار ۷۵۰ + ۲۰ گرم عیار ۷۰۵ تحویل میدهی → معادل ۷۵۰ ورودی = ۲۸٫۸۰۰ گرم. آبشده ۲۹٫۵ گرم با ری ۷۲۰ برمیگردد → معادل ۷۵۰ خروجی = ۲۸٫۳۲۰ گرم. افت = ۰٫۴۸۰ گرم (۱٫۶۷٪) — در محدودهٔ عادی.
#دو اتصال خودکار
موقع ثبت ری، دو تیک داری که هر دو پیشفرض روشناند:
| تیک | چه میکند |
|---|---|
| افزودن به موجودی آبشده | یک ردیف آبشده با همان وزن، ری، ریگیری و شمارهٔ قبض در کالا و انبار ← آبشده و متفرقه میسازد |
| ثبت کارمزد در مخارج | کارمزد ذوب را با بابتِ «کارمزد ذوب» به هزینهها اضافه میکند |
هر کدام فقط یک بار انجام میشود؛ اگر قبلاً ثبت شده باشد تیک غیرفعال میشود و سند تکراری ساخته نمیشود. اگر موقع ثبت ری تیک را برداری، بعداً از دکمهٔ «به موجودی» در همان ردیف میتوانی اضافهاش کنی.
#شاخصهای بالای صفحه
در ذوب (وزن معادل ۷۵۰ که هنوز دستِ ریگیری است) · آبشدهٔ برگشتی · افت یا سرک کل · کارمزد کل. با چیپهای بالا هم میتوانی فقط قبضهای باز یا فقط برگشتهها را ببینی.
#قبض چاپی
دکمهٔ رسید روی هر ردیف، قبض ذوب را باز میکند: اقلام ورودی با وزن و عیار و معادل ۷۵۰، وزن و ری برگشتی، افت و کارمزد، و جای امضای تحویلدهنده و ریگیری. یک نسخه دست خودت، یک نسخه دست ذوبخانه.
#نکتهها
- طرف حساب اختیاری است. اگر طلا مالِ خودِ مغازه است خالی بگذار؛ اگر متعلق به یک سازنده یا مشتری است نامش را انتخاب کن تا روی قبض بیاید.
- نام ذوبخانهٔ تازه که تایپ کنی، خودکار به فهرست ریگیریها اضافه میشود و دفعهٔ بعد پیشنهاد داده میشود.
- حذف قبض ردیف موجودی و کارمزدی را که خودِ همان قبض ساخته بود هم پاک میکند، ولی به هیچ رکورد دیگری دست نمیزند.
- این دفتر ماندهی طرف حساب را جابهجا نمیکند؛ یک دفتر فیزیکیِ ردیابی طلاست. اگر بابت ذوب با کسی حساب مالی داری، سند دریافت/پرداختِ عادی بزن.
- کنار هر قبضِ ذوب یک آیکون نمودار هست که همان آبشده را در گردش موجودی باز میکند — برای وقتی که وزنِ آبشدهٔ روی ترازو با دفتر جور درنمیآید. جستوجوی آن صفحه نام ریگیری و شمارهٔ قبض را هم میشناسد.
#۱۹. پیوست سند
به هر سند میتوانی فایل ضمیمه کنی: فیش واریزی، رسید کارتخوان، تصویر کارت ملی، قرارداد یا هر مدرکی که باید کنار همان شمارهٔ سند بماند.
#چطور
در صفحهٔ ثبت سند دکمهٔ «پیوست» بالای صفحه است. عدد کنار دکمه تعداد پیوستهای فعلی را نشان میدهد. سه راه افزودن داری: انتخاب فایل، رها کردن فایل روی پنجره (drag & drop)، یا دوربین برای عکس گرفتن مستقیم.
#چه فایلهایی
عکس (JPG/PNG/WEBP/GIF)، PDF، متن، Word و Excel — تا ۸ مگابایت برای هر فایل. فایلهای اجرایی و ناشناخته رد میشوند.
هر پیوست را میتوانی تغییر نام بدهی (مثلاً «فیش بانک ملت ۱۴۰۵/۰۵/۱۳») یا حذف کنی. فایلها روی سرور ذخیره میشوند و در نسخهٔ پشتیبان هم میآیند.
#۲۰. پیشنویس تکفروشی
وقتی مشتری میپرسد «این چند؟»، لازم نیست سند بزنی. دکمهٔ «پیشنویس تکفروشی» در صفحهٔ ثبت سند یک ماشینحسابِ قیمت باز میکند که هیچ سندی ثبت نمیکند و روی ماندهها اثری ندارد.
#چه میدهد
قیمت نهایی با همان فرمول مالیاتیِ سند فروش حساب میشود: ارزش طلا + اجرت + سود فروشنده + مالیات ارزش افزوده (مالیات فقط روی اجرت و سود). نرخ، درصد سود و درصد مالیات را میتوانی همانجا عوض کنی.
#تعویض طلای مشتری
ردیف «طلای متفرقهٔ مشتری» را اضافه کن تا طلایی که مشتری میآورد از مبلغ کم شود و مابهالتفاوت معلوم گردد — همان چیزی که مشتری واقعاً باید بپردازد.
#امکانات کمکی
- «این عدد از کجا آمد؟» — تفکیک کامل هر ردیف: ارزش طلا، اجرت، سود، مالیات. برای وقتی که مشتری توضیح میخواهد.
- حالت نمایش — بزرگنمایی برای نشان دادن به مشتری.
- پنجرهٔ جدا — برای مانیتور دومی که روبهروی مشتری است؛ با پنجرهٔ اصلی همگام میماند.
- تبدیل به سند فروش — اگر مشتری راضی شد، با یک دکمه همهٔ ردیفها به سند فروش منتقل میشوند (ردیف تعویض بهصورت «ورود» ثبت میشود). فقط طرف حساب را انتخاب کن و ذخیره بزن.
پیشنویس در همان مرورگر باقی میماند، پس اگر صفحه بسته شد از دست نمیرود.
#۲۱. نسخهٔ پشتیبان
در تنظیمات ← نسخهٔ پشتیبان، دکمهٔ «دریافت نسخهٔ پشتیبان» یک فایل zip میدهد که هم دادهها و هم همهٔ عکسهای اجناس، عکس اشخاص و پیوستهای سند را در خود دارد. پس با بازگردانی، هیچ عکسی گم نمیشود.
عکسهایی که در هیچ رکوردی استفاده نشدهاند داخل پشتیبان نمیآیند — این عمدی است تا فایل بیجهت سنگین نشود.
#بازگردانی
دکمهٔ «بازگردانی» فایل zip (یا فایل JSON دادهٔ خام) را میپذیرد. همهٔ دادههای فعلی جایگزین میشوند، پس قبلش یک پشتیبان از وضعیت فعلی بگیر. یک تأیید هم پرسیده میشود.
#توصیه
هفتهای یک بار پشتیبان بگیر و فایل را جای دیگری (فلش، درایو ابری، رایانهٔ دیگر) نگه دار. پشتیبانی که روی همان سرور بماند، در برابر خرابیِ سرور کاری از دستش برنمیآید.
#۲۲. وام و تسهیلات بانکی
وقتی از بانک وام میگیری، پول به حسابت میآید ولی همان لحظه همان مبلغ (بهعلاوهٔ سود) بدهیِ تو به بانک است. این دو تا با هم فرق دارند و باید جدا نگه داشته شوند.
#اشتباه رایج: زدنِ وام روی خودِ حساب بانکی
اگر دریافتِ وام را مستقیم روی حساب بانکی ثبت کنی، موجودی آن حساب بالا میرود و دیگر معلوم نیست چقدرش پولِ خودت است و چقدرش پولِ بانک. ماندهٔ حساب بانکی از این به بعد دروغ میگوید و صورت سود و زیان هم خراب میشود.
قاعده: سندِ وام از سندِ حساب بانکی جداست. هر وام حسابِ مستقلِ خودش را دارد.
#وام چطور کار میکند
در صفحهٔ وام و تسهیلات با «+ وام جدید» وام را میسازی. هنگام ساخت اینها را میدهی:
| فیلد | توضیح |
|---|---|
| نام وام | مثلاً «وام ملی — فردوسی» |
| بانک | بانکِ وامدهنده |
| مبلغ وام (اصل) | پولی که واقعاً به حسابت واریز میشود |
| سود و کارمزد | مبلغی که بانک اضافه بر اصل از تو میگیرد |
| واریز به حساب | حساب بانکیای که پولِ وام به آن آمده |
| تعداد و مبلغ قسط | برای پیگیری اقساط (اختیاری) |
با ثبت، دو سند خودکار زده میشود:
- روی حساب بانکی: یک سندِ دریافت → موجودیِ بانک به اندازهٔ اصلِ وام بالا میرود.
- روی حساب وام: یک سندِ پرداخت → بدهیِ تو به بانک ثبت میشود.
سود و کارمزد فقط سندِ سومی روی حساب وام میزند: بدهی را زیاد میکند ولی هیچ پولی به حساب بانکی اضافه نمیکند (چون سود پولِ نقد نیست، تعهد است).
مثال: موجودی «ملی فردوسی» ۴٬۵۸۰٬۰۰۰٬۰۰۰ است. وام ۳٬۰۰۰٬۰۰۰٬۰۰۰ با ۸۰٬۰۰۰٬۰۰۰ سود میگیری:
| بعد از ثبت | موجودی بانک | بدهیِ وام |
|---|---|---|
| دریافت اصلِ وام | ۷٬۵۸۰٬۰۰۰٬۰۰۰ | ۳٬۰۰۰٬۰۰۰٬۰۰۰ |
| افزودن سود و کارمزد | ۷٬۵۸۰٬۰۰۰٬۰۰۰ (بدون تغییر) | ۳٬۰۸۰٬۰۰۰٬۰۰۰ |
#پرداخت قسط
روی کارت هر وام دکمهٔ «پرداخت قسط» هست. روش پرداخت را انتخاب میکنی:
| روش | اثرش |
|---|---|
| حواله از حساب بانکی | بدهیِ وام کم میشود و موجودیِ آن حساب بانکی هم کم میشود |
| نقدی | فقط بدهیِ وام کم میشود |
| چک دیگران (چکِ مشتری) | بدهیِ وام کم میشود و آن چک به وضعیت «خرج شده» میرود — چون برگه را به بانک تحویل دادهای. بانک، شماره، سررسید و سندِ مبدأ در زندگینامهٔ چک میماند و در صورت اشتباه میتوانی آن را بازگردانی |
ادامهٔ مثال بالا: قسط ۵۶٬۰۰۰٬۰۰۰ با حواله → بانک میشود ۷٬۵۲۴٬۰۰۰٬۰۰۰ و بدهی ۳٬۰۲۴٬۰۰۰٬۰۰۰. بعد قسط ۱۰۵٬۰۰۰٬۰۰۰ با چکِ مشتری → بانک دستنخورده میماند و بدهی میشود ۲٬۹۱۹٬۰۰۰٬۰۰۰.
#سود و کارمزدِ بعدی
اگر بانک وسطِ کار جریمه، کارمزد یا سودِ تازه اضافه کرد، دکمهٔ «+ سود و کارمزد» همان کار را میکند: بدهی زیاد میشود، موجودیِ بانک دست نمیخورد.
#خواندنِ کارتِ وام
هر وام یک کارت دارد با نوارِ پیشرفت و چهار عدد:
- ماندهٔ بدهی — چقدر هنوز به بانک بدهکاری (قرمز یعنی بدهکار).
- پرداختشده — جمعِ اقساطی که دادهای.
- کل بازپرداخت — اصل + همهٔ سود و کارمزدها.
- اقساط — چند قسط از چند قسط.
وقتی ماندهٔ بدهی صفر شود، برچسبِ وام از «فعال» به «تسویه شده» تغییر میکند.
دکمهٔ «سند وام» همهٔ ردیفها (دریافت، سودها و اقساط) را بهترتیب تاریخ نشان میدهد.
حذف وام: حذفِ یک وام همهٔ سندهای مربوط به آن را هم پاک میکند. قبلش پشتیبان بگیر.
#۲۳. چند صفحه همزمان: میزِ کارِ ساعتِ شلوغی
ساعتِ شلوغیِ مغازه است. مشتریای آمده که فاکتورش سی قلم جنس است، سرِ بعضیشان چانه میزند و کارش دستِکم نیم ساعت طول میکشد. وسطِ همین کار، مشتری بعدی میرسد که فقط یک آبشده آورده و میخواهد تحویل بدهد و برود. مشتری سوم فقط قیمتِ تهحسابش را میخواهد.
بدونِ سربرگ باید سندِ نیمهتمام را ببندی، برگردی، و بعد از دستت در برود که چه به چه بوده. با سربرگها هیچکدام از این کارها بسته نمیشوند؛ همه کنارِ هم روی میزِ کار باز میمانند.
نوارِ سربرگها زیر نوار بالایی است و هر صفحهٔ باز یک سربرگ دارد. عنوانِ سربرگِ سند نوع سند + نام طرف حساب است (مثلاً «فروش — علی رضایی») و اگر آن سند ذخیره نشده باشد یک نقطهٔ طلایی کنارش روشن میشود؛ پس با یک نگاه میفهمی کدام کار هنوز روی هواست.
#کارها
| کار | چطور |
|---|---|
| باز کردن سربرگ تازه | Ctrl+کلیک (در مک ⌘+کلیک) روی گزینهٔ منو — یا کلیک وسطِ موس روی آن |
| جابهجایی بین سربرگها | کلیک روی سربرگ — یا Alt+۱ تا Alt+۹ (و Alt+۰ برای آخرین) |
| چرخیدن بین سربرگها | Alt+← بعدی · Alt+→ قبلی |
| بستن سربرگ | دکمهٔ ✕ روی سربرگ — یا کلیک وسطِ موس روی خودِ سربرگ — یا Alt+W |
| مرتب کردن | سربرگ را بکش و جای دیگری از نوار رها کن |
| فهرست همهٔ صفحههای باز | چیپِ «n صفحه» کنارِ نوار |
| پنجرهٔ جدا | دابلکلیک روی سربرگ → همان صفحه (با همان سندِ نیمهکاره) به یک پنجرهٔ مستقل میرود |
کلیکِ عادی روی منو مثل قبل عمل میکند: همان سربرگِ فعلی به صفحهٔ جدید میرود و سربرگِ تازهای ساخته نمیشود.
میانبرهای Alt به جای کلید روی صفحهکلید بستهاند نه به حرفِ رویش؛ پس چه فارسی بنویسی چه انگلیسی، همان کلیدها کار میکنند. وقتی داری فاکتورِ سیقلمی میزنی، دستت روی کیبورد میمانَد.
#سندها گم نمیشوند
هر سربرگ سندِ خودش را نگه میدارد. اگر وسطِ سندِ مشتری الف با Ctrl+کلیک سربرگ تازه باز کنی و سندِ مشتری ب را بزنی، با برگشتن به سربرگ اول سندِ الف دقیقاً همانطور که بود برمیگردد — ردیفها، طرف حساب، نرخ، همه.
اگر بخواهی سربرگی را ببندی که سندِ ذخیرهنشده دارد، پنل قبلش تأیید میگیرد تا اشتباهی کارت از بین نرود. سندی که قبلاً ذخیره شده بدونِ پرسش بسته میشود؛ پرسشِ بیمورد باعث میشود آدم به پرسشِ باموردش هم بیاعتنا شود. آخرین سربرگ بسته نمیشود (چون آنوقت صفحهای باقی نمیماند).
#حتی رفرش هم کارت را نمیبلعد
میزِ کارت در همین مرورگر نگه داشته میشود. اگر رفرش کنی، اشتباهی تبِ مرورگر را ببندی، یا برق برود و کامپیوتر خاموش شود، دفعهٔ بعد که پنل را باز کنی همان سربرگها با همان ترتیب و همان سندهای ذخیرهنشده برمیگردند. با رفرش داخل پنل همان سربرگ فعال حفظ میشود؛ اما وقتی از بیرون دوباره وارد آدرس پنل ادمین میشوی، صفحهٔ نخست روی داشبورد باز میشود تا آخرین سربرگ «دستیار هوشمند» جای صفحهٔ اصلی را نگیرد. سربرگها و سندهای قبلی همچنان در نوار باقی میمانند.
- میزِ کار برای هر دفتر جداست؛ با رفتن به دفترِ دیگر، سربرگهای آن دفتر بالا میآیند نه این یکی. - میزِ کارِ کهنه (بیشتر از یک هفته) دیگر برنمیگردد. - صفحهای که دسترسیاش از کاربر گرفته شده باشد، در بازگشت باز نمیشود.
#پنجرهٔ جدا برای مانیتور دوم
«دو تا مانیتور دارم؛ میخواهم صفحهٔ خلاصهوضعیت را جدا کنم ببرم روی مانیتور دوم.» با دابلکلیک روی سربرگ، آن صفحه در پنجرهٔ مستقل باز میشود. این پنجره سایدبار و نوار سربرگ ندارد و تمامعرض است.
جدا کردن یعنی جابهجایی، نه کپی: اگر سربرگِ یک سندِ نیمهکاره را جدا کنی، خودِ همان سند به پنجرهٔ تازه میرود و در پنجرهٔ اصلی دو نسخهٔ سردرگمکننده نمیماند. بقیهٔ صفحهها دستنخورده سرِ جایشان هستند و هر وقت آن پنجره را ببندی، هیچ اتفاقی برای بقیه نمیافتد.
- اگر پنجرهٔ جداشده سندِ ذخیرهنشده داشته باشد، خودِ مرورگر پیش از بستنش میپرسد. - اگر مرورگر جلوِ باز شدنِ پنجره را بگیرد (pop-up blocker)، هیچ چیزی جابهجا نمیشود و سربرگ سرِ جایش میماند؛ پیامش را میبینی. - هر دو پنجره روی همان دادهٔ سرور کار میکنند؛ سندی که در یکی ذخیره شود در دیگری هم دیده میشود.
#۲۴. تبدیل متفرقه به ویترین و «عیار شخصی»
طلای متفرقهای که از مشتری میخری همیشه سرِ راهش ذوب نیست. گاهی یک انگشتر یا سرویسِ سالم و تمیز است که مستقیم میشود روی ویترین گذاشت و دوباره فروخت. عیارِ این جنسها معمولاً ۷۴۰ است، ولی وقتی روی ویترین میفروشیشان با ۷۵۰ حساب میکنی. همان ۱۰ واحد اختلاف، سودِ توست — و پنل دو راه برای ثبتش دارد.
#راه یکم: فقط ستون «عیار شخصی» (سریع، بدون سند اضافه)
جنس در انبار «آبشده و متفرقه» میماند و کاری نمیکنی تا وقتی فروخته شود. سرِ فروش:
- در سند فروش، ستون شرح را روی «۱۰ متفرقه سالم» بگذار.
- ستون عیار را روی عیارِ واقعیِ جنس بگذار (مثلاً ۷۴۰).
- ستون «عیار شخصی» را ۷۵۰ بزن.
همین. پنل مبلغ و وزنِ معادلِ مشتری را با ۷۵۰ حساب میکند، ولی میداند جنس واقعاً ۷۴۰ بوده. زیرِ سلول یک برچسب سبز مثل +۰٫۱۹۵ گ میبینی و پایینِ سند هم چیپِ «سود عیار» ظاهر میشود.
| مثال | عدد |
|---|---|
| وزن | ۱۴٫۶۵۰ گرم |
| عیار جنس | ۷۴۰ |
| عیار شخصی | ۷۵۰ |
| معادلِ واقعی | ۱۴٫۴۵۵ گ۷۵۰ |
| معادلِ محاسبه با مشتری | ۱۴٫۶۵۰ گ۷۵۰ |
| سود عیار | ۰٫۱۹۵ گ۷۵۰ |
«عیار شخصی» خالی یعنی خاموش. همهٔ اسناد قبلی و ردیفهای معمولی دقیقاً مثل قبل کار میکنند. در خرید همین کار به ضرر توست، پس پنل علامت را برعکس نشان میدهد. روی فاکتور مشتری عیارِ شخصی چاپ میشود (نه عیارِ فیزیکی) تا وزن معادل۷۵۰ با عددِ عیار بخواند. ولی موجودیِ انبار با عیارِ شخصی تکان نمیخورد. در گردش موجودی همان ۷۴۰ِ فیزیکی از انبار خارج میشود — چون واقعاً همان تکه از مغازه بیرون رفته، نه بیشتر. آن ۱۰ واحد سودِ حساب است، نه طلای جابهجاشده.
عیبش: جنس همچنان قاتیِ انبار متفرقه است؛ سرِ انبارگردانی نمیفهمی کدام تکه روی ویترین است و کدام برای ذوب.
#راه دوم: سندِ «تبدیل متفرقه به ویترین» (مرتب، پیشنهادی)
جنس را همان اول از انبار متفرقه بیرون میآوری و به موجودی اجناس میبری. مسیر:
کالا و انبار → آبشده و متفرقه → دکمهٔ «تبدیل متفرقه به ویترین» (یا آیکونِ حلقه روی همان ردیف).
در پنجرهای که باز میشود:
| فیلد | توضیح |
|---|---|
| از موجودی آبشده و متفرقه | ردیفی که میخواهی از آن بردار کنی (متفرقهها اول فهرستاند) |
| وزن مصرفی | چند گرم از آن ردیف برداشته میشود (پیشفرض: کلِ ردیف) |
| عیار متفرقه | عیارِ واقعی، از خودِ ردیف پر میشود (۷۴۰) |
| نام جنسِ ویترین | مثلاً «کار شرکتی ۷۵۰» — اگر تعریف نشده باشد خودکار به کاتالوگ اضافه میشود |
| عیار فروش | ۷۵۰ |
| تعداد قطعه | اگر چند تکه است، وزنِ هر قطعه خودکار حساب میشود |
| اجرت فی هر گرم | اختیاری |
وسطِ پنجره یک پیشنمایش زنده است: خروج از متفرقه، ورود به ویترین، و سود عیار — و باقیماندهٔ آن ردیف بعد از تبدیل.
دکمهٔ «ثبت تبدیل» سه کار میکند:
- یک سند داخلی با دو ردیف میسازد: ▼ خروج متفرقه با عیار ۷۴۰ و ▲ ورود جنسِ ویترین با عیار ۷۵۰.
- وزن را از ردیفِ متفرقه کم میکند (اگر صفر شد، ردیف حذف میشود).
- جنس را با یک بارکد تازه به «موجودی اجناس» اضافه میکند و برچسب «تبدیلی» میگیرد.
مهم: سرِ فروشِ این جنس، عیارش دیگر ۷۵۰ است و سودِ عیار قبلاً شناسایی شده. پس ستون «عیار شخصی» را خالی بگذار تا سود دوباره شمرده نشود. اگر جنس نفروخت و تصمیم گرفتی ذوبش کنی، کافی است همین دو ردیف را برعکس ثبت کنی تا سودِ شناساییشده خنثی شود.
مزیتش: در «خلاصه وضعیت» و «موجودی اجناس» این جنس جداگانه شمرده میشود و میدانی دقیقاً چه چیزی روی ویترین داری.
#کجا سود را میبینی
در گزارشها → سود و زیان، اگر در دوره «عیار شخصی» بهکار رفته باشد، یک کارتِ «سود عیار شخصی» با مقدارِ گرمی و ریالیاش میآید و یک خط هم در صورت سود و زیان اضافه میشود. این سود داخلِ خطِ «ارزش طلای خالصِ انباشته» لحاظ شده است — یعنی طلایی که واقعاً در گاوصندوق مانده، درست حساب میشود.
#۲۵. ریز ورود و خروج و جمع ردیفهای انتخابی
وسط ثبتِ یک سندِ تکفروشی، سؤالِ همیشگی این است: «آنچه نوشتم با آنچه روی ترازوست یکی است؟» دو ابزار در پای همان صفحهٔ سند این را جواب میدهند و هیچکدام چیزی را ذخیره یا تغییر نمیدهند — فقط نشان میدهند.
#الف) نشانِ شناورِ جمع (انتخاب چند ردیف)
روی هر جای خالیِ یک ردیف کلیک کن (نه روی خانههای ورودی). ردیف آبی میشود و پایینِ صفحه یک نشانِ شناور میآید با: تعداد ردیف، وزن، وزن ۷۵۰، تعداد سکه و مبلغ.
| کار | کلید |
|---|---|
| انتخاب یک ردیف | کلیک |
| افزودن یا برداشتنِ یک ردیف | Ctrl (روی مک ⌘) + کلیک |
| انتخاب یک بازه | Shift + کلیک روی ردیف آخر |
| برداشتنِ انتخاب | کلیک دوباره روی همان ردیف، یا Esc، یا ✕ روی نشان |
کاربرد واقعی: دو متفرقهای را که از مشتری گرفتی با Ctrl انتخاب کن؛ نشان میگوید ۳۰٫۷۲۰. همان دو قلم را با هم روی ترازو بگذار. اگر عدد یکی نبود، یعنی موقع ثبت یک وزن اشتباه خورده است.
نشان با رفتن به صفحهٔ دیگر، باز کردنِ سندِ دیگر، یا افزودن و حذفِ ردیف خودش پاک میشود تا هرگز عددِ کهنه نشانت ندهد.
#ب) پنل «ریز ورود ـ خروج»
زیر جمعِ سند، دکمهٔ «ریز ورود ـ خروج» پنلی را باز میکند که همان اقلامِ سند را در دو محور میچیند:
- گروهِ ذاتی: آبشده · متفرقه · جنس · سکه · نقد و اجرت
- جهتِ جریان: ورود (چیزی که وارد مغازه شده) و خروج (چیزی که از مغازه بیرون رفته)
دو حالت دارد:
| حالت | چه میدهد |
|---|---|
| به تفکیک | برای هر گروه یک کارت جدا: وزن، وزن ۷۵۰، اجرت (اگر باشد) و مبلغِ ورود و خروج |
| جمع کل | یک جدولِ تمامعرض: کلِ ورود، کلِ خروج و خالص — با ستونهای سکه و «سود و مالیات» هر وقت مقدار داشته باشند |
نکتههای خواندنِ درست:
- جهت از ستون «تشخیص» میآید، نه از نوع سند. یک ردیفِ مرجوع در سند فروش، در پنل زیر ورود مینشیند — چون واقعاً طلا برگشته به مغازه. در سندِ «سایر» هم تشخیصهای ورود/خروج مستقیم همین کار را میکنند و ردیفِ بیتشخیص اصلاً شمرده نمیشود.
- گروهِ آبشده یعنی ردیفهایی با کد شرح ۱ یا ۳؛ متفرقه یعنی کد ۲ یا ۱۰؛ طلای بدون کد شرح، جنس حساب میشود. پس اگر میخواهی تفکیک درست دربیاید، ستون «شرح» را پر کن (بخش ۵).
- خانهٔ بیمقدار خالی میماند، نه صفر — همان قراردادِ سند چاپی.
- ردیف خالص = ورود منهای خروج. این عدد همیشه دقیقاً برابرِ اثری است که سند روی ماندهٔ طرف حساب میگذارد؛ پنل حساب تازهای نمیسازد، فقط همان حساب را از زاویهٔ انبار نشان میدهد.
نکتهٔ ترازو: وزنِ روی ترازو معمولاً از وزنِ پنل بیشتر است، چون سنگ و پلاستیک و بستهٔ کار هم روی کفهٔ ترازوست. اختلاف را با همان وزنِ سنگ بسنج، نه با صفر.
این بخش با بخش بعدی فرق دارد. پنلِ اینجا فقط همین یک سند را میشکافد — سرِ ثبت، برای اینکه مطمئن شوی درست نوشتهای. اگر اختلافِ ترازو مالِ همین سند نبود و به کلِ موجودیِ یک قلم برمیگشت، جای درست گردش موجودی است که همهٔ اسناد آن قلم را در طول زمان پشت سر هم میچیند.
#۲۶. سند چاپی: فاکتور و قبض
سندی که چاپ یا دانلود میکنی همان قالب کاغذیِ مغازه است، اما چیدمان فاکتور حالا از مرکز چاپ قابل تنظیم است. از روی هر سند دکمهٔ «چاپ فاکتور» را بزن؛ پیشنمایش زنده در کنار تنظیمات باز میشود. در تنظیمات → مرکز چاپ فاکتور هم میتوانی همین صفحه را با آخرین سند باز کنی.
#مرکز چاپ و پیشنمایش — v101
- کاغذ A4 یا A5 و جهت افقی یا عمودی را انتخاب کن.
- حاشیهٔ بالا، راست، پایین و چپ بر حسب میلیمتر و اندازهٔ فونت بین ۸ تا ۱۴ قابل تنظیم است.
- ستونهای شرح، وزن، عیار، وزن ۷۵۰، فی و مبلغ مستقل روشن یا خاموش میشوند.
- لوگو، اطلاعات فروشگاه، پاورقی، ریز سود و مالیات، ردیف تخفیف و ردیف خرید طلا انتخابیاند.
- ماندهٔ قبلی و ماندهٔ نهایی مستقلاند؛ محل جمعها نیز میتواند کنار ریز محاسبات یا تمامعرض پایین باشد.
- عیار را میتوان بر مبنای سامانه یا ۲۴ نمایش داد. برای نمونه عیار ۷۵۰ در حالت ۲۴ برابر ۱۸ نمایش داده میشود.
- گزینهٔ سربرگ آماده فضای بالای کاغذ را برای سربرگ از پیش چاپشده خالی میگذارد.
- گزینهٔ حریم حواله، نام طرف مقابل را فقط از نسخهٔ چاپی پنهان میکند و دادهٔ حسابداری را تغییر نمیدهد.
با تغییر هر گزینه، پیشنمایش فوراً تازه میشود؛ این کار نه سند را میبندد و نه دفعات چاپ را زیاد میکند. «ذخیره تنظیمات» انتخابها را برای فاکتورهای بعدی نگه میدارد. زدن «چاپ فاکتور» نیز ابتدا همان تنظیمات را ذخیره میکند و سپس شمارندهٔ چاپ سند را یک واحد افزایش میدهد. تعداد دفعات چاپ در سربرگ فاکتور و کنار پیشنمایش دیده میشود.
مرز تنظیمات برنامه و سیستم: اندازه، جهت، حاشیه و محتوای فاکتور در مرکز چاپ تنظیم میشوند؛ اما انتخاب چاپگر، تعداد نسخه و گزینههای سختافزاری در پنجرهٔ چاپ سیستمعامل انجام میشود. اگر چاپگری در آن پنجره نیست، درایور آن باید روی دستگاه نصب شود.
نام، نشانی، متن پایین فاکتور و نشانی تصویر لوگو از بخش «اطلاعات فروشگاه و نرخ» تنظیم میشوند. آدرس لوگو باید یک نشانی تصویری معتبر یا دادهٔ تصویری data:image/... باشد.
#نقشهٔ سند از بالا به پایین
| ناحیه | چه چیزی آنجاست |
|---|---|
| سربرگ (بیرون کادر) | راست: لوگو + نام طرف حساب · وسط: «هوالرزاق» و نام فروشگاه · چپ: کادر خطچینِ شمارهٔ سند، تاریخ، شمارهٔ سند و یک کادر خطچینِ خالی برای یادداشت دستی |
| نشانی | یک خط تمامعرض زیر سربرگ |
| کادر گِرد اصلی | نوار نام و کد و تلفن طرف حساب، جدول اقلام، جمعبندی، شعار فروشگاه |
| پاورقی (بیرون کادر، بدون خط) | امضای خریدار · امضای فروشنده · «صدور سند توسط: نام کاربر — تاریخ و ساعت» |
#جدول اقلام
ستونها از راست: شماره، شرح، وزن به گرم، عیار، وزن ۷۵۰، قیمت هر، مبلغ.
- خانهای که مقدار ندارد خالی میماند — نه خط تیره، نه صفرِ ساختگی.
- زیر آخرین ردیف یک فضای خالی میماند تا سند همیشه ارتفاع یکسان و کاغذیِ خودش را داشته باشد، حتی با یک قلم.
- اجرت، سود فروشنده، مالیات، تخفیف و پرداختی داخل ستون شرح میآیند تا جدول شلوغ نشود.
#جمعبندی سهستونه
سمت راستِ پایینِ کادر، چهار ردیف پشت سر هم میآید و هر ردیف سه خانه دارد: عنوان | گرم | ریال و سکه.
| ردیف | یعنی |
|---|---|
| جمع فروش / جمع خرید | جمعِ خودِ اقلام همین سند |
| مانده سند | اثر همین سند روی حساب طرف مقابل |
| مانده قبلی | ماندهٔ طرف حساب پیش از این سند |
| مانده نهایی | مانده بعد از این سند — این ردیف کادر دارد چون عددی است که طرف حساب دنبالش میگردد |
- ریال و گرم با پیشوند بد (بدهکار) یا بس (بستانکار) میآیند.
- سکهها زیر خانهٔ ریالی، هر نوع در یک خط: مثلاً
بس ۱ ربعوبد ۱ نیم. - ریز مالیات در نیمهٔ خالیِ سمت چپِ همین ناحیه چاپ میشود و ردیفهای جمعبندی را بههم نمیزند.
باگی که اینجا اصلاح شد: پیش از این، سکههای «مانده نهایی» اثرِ خودِ سند را نمیگرفتند و همان سکههای «مانده قبلی» تکرار میشدند. حالا اگر با این سند یک ربع تسویه شود، مانده نهایی۰ ربعنشان میدهد نه۱ ربع.
#اعداد
روی سند چاپی جداکنندهٔ هزارگان ٬ و اعشار ٫ فارسی است (۱٬۷۴۴٬۴۵۲٬۹۷۹ و ۱٫۰۰۰g). در بقیهٔ رابط کاربری همان قالبِ قبلی میماند تا ورودیهای عددی دستنخورده بمانند.
#قبض ذوب
همان نقشه را دارد، با این تفاوتها: نوار بالای کادر «قبض ذوب و ریگیری — نام ریگیری» است، جدول بهجای مبلغ ستون وزن ۷۵۰ دارد، و جمعبندی شاملِ جمع وزن ورودی، معادل ۷۵۰، آبشدهٔ برگشتی، افت یا سرک و کارمزد است. قبضی که هنوز برنگشته، بهجای افت، خطِ «در ذوب — هنوز ری نخورده است» میگیرد.
#فاکتور سایت فروشگاه
فاکتوری که مشتری از سایت دانلود میکند هم به همین قالب درآمده. ماندههای قبلی و نهاییِ آن از کارت حساب و کارت وزنیِ همان مشتری خوانده میشود، دقیقاً روی ردیفِ همین فاکتور.
اگر فاکتور به مشتریِ ثبتشده وصل نباشد یا کارت حساب در دسترس نباشد، آن خانهها خالی میمانند. عمداً صفر نمیگذاریم، چون «صفر» یعنی تسویه و این با «نمیدانیم» فرق دارد.
#۲۷. گردش موجودی: کاردکس هر قلم
منو → انبار و دارایی → گردش موجودی.
#این صفحه برای چه ساخته شد
یک اتفاقِ همیشگی در مغازه: جنس را روی ترازو میگذاری، ۲۲۷٫۷۳۰ درمیآید؛ برنامه میگوید ۲۴۷٫۷۳۰. بیست گرم اختلاف. جنس گم نشده — یک سند جا مانده یا یک سند دوبار خورده. پیدا کردنش با ورقزدنِ دفتر روزانه ساعتها طول میکشد.
«گردش موجودی» همان دفتر است، ولی فقط برای یک قلم: هر ورود و خروجِ آن قلم به ترتیب تاریخ، با ماندهٔ بعد از هر حرکت. از بالا پایین میآیی تا جایی که مانده با واقعیت جور درنمیآید — همانجا سند خرابت است.
#دو ستون صفحه
سمت راست — انتخاب قلم: فهرست همهٔ قلمهای قابل ردیابی. هم آنچه در اسناد حرکت کرده، هم آنچه در انبار خوابیده و هنوز سندی نخورده.
- جستجو با نام، عیار، بارکد، نام ریگیری یا شمارهٔ قبض ذوب.
- چیپهای آبشده / متفرقه / جنس / سکه فهرست را باریک میکنند.
- کنار هر قلم، شمارِ حرکتهایش نوشته شده و قلمهای موجود در انبار علامت دارند.
سمت چپ — گزارش: بازهٔ زمانی، چهار کارت خلاصه، جعبهٔ تطبیق، و جدول کاردکس.
#چند قلم با هم — چیزی که در نرمافزارهای قدیمی نبود
میتوانی چند قلم را همزمان تیک بزنی؛ مثلاً هر سه آبشدهٔ ریگیریهای مختلف. کاردکس آنها با هم ادغام میشود و یک ماندهٔ مشترک میسازد. در این حالت نامِ هر قلم در ستون شرح میآید تا حرکتها قاطی نشوند.
در برنامههای مشابه برای دیدن گردشِ چند آبشده باید به دفتر روزانه پناه میبردی. اینجا لازم نیست.
#بازهٔ زمانی
چیپهای آماده: امروز، یک هفته، یک ماه، شش ماه، از اول این ماه، از ابتدای دوره، دستی.
بازهٔ کوچکتر سریعتر باز میشود. هر حرکتی که پیش از شروع بازه باشد حذف نمیشود؛ در ردیف «موجودی ابتدای دوره» جمع میشود. پس ماندهٔ آخر جدول در هر بازهای درست است.
#چهار کارت بالای گزارش
| کارت | یعنی |
|---|---|
| ماندهٔ ابتدای دوره | آنچه پیش از شروع بازه در دست بوده |
| جمع ورود | همهٔ خریدها، برگشتیهای فروش و ورودیهای بازه |
| جمع خروج | همهٔ فروشها، برگشتیهای خرید و خروجیهای بازه |
| ماندهٔ دفتری در پایان | ابتدای دوره + ورود − خروج |
#جعبهٔ تطبیق: کارِ اصلی همینجاست
زیر کارتها یک کادر است با سه خانه:
- ماندهٔ دفتری — آنچه برنامه میگوید.
- وزنِ روی ترازو — قابل ویرایش. اگر همین قلم در انبار ثبت شده باشد، خودکار پر میشود؛ وگرنه عددِ ترازو را خودت بزن.
- اختلاف — تفاضل این دو.
اگر اختلاف صفر باشد کادر سبز میشود. اگر نه، برنامه میگوید دنبال چه بگردی:
| حالت | تشخیص |
|---|---|
| انبار بیشتر از دفتر | یا یک خروج اضافه ثبت شده، یا یک ورود هنوز سند نخورده |
| دفتر بیشتر از انبار | یا یک ورود دو بار ثبت شده، یا یک خروج هنوز سند نخورده |
و مهمتر: سندهای مشکوک را خودش پیدا میکند. دو نوع اتهام میزند:
- «تکراری؟» — دو حرکتِ همتاریخ، همقلم و دقیقاً هماندازه. کلاسیکترین حالتِ سندِ دوبار ثبتشده.
- «هماندازهٔ اختلاف» — حرکتی که مقدارش دقیقاً برابر اختلاف است و در جهتِ درست هم هست.
روی هر دکمهٔ متهم که بزنی، همان سند باز میشود تا بررسی یا اصلاحش کنی. این همان جستوجوی دستی است که حالا خودکار شده.
#جدول کاردکس
| ستون | توضیح |
|---|---|
| تاریخ / سند | تاریخ و شمارهٔ سند |
| شرح | طرف حساب + ورود یا خروج + نوع سند (+ نشانِ ↩ مرجوعی و «بابت») |
| وزن دریافتی | ستون آبی — هرچه وارد شده |
| وزن پرداختی | ستون قرمز — هرچه خارج شده |
| ماندهٔ وزن | ستون طلایی — مانده بعد از همین حرکت |
- اگر قلم تعدادی هم داشته باشد (سرویس، سکه)، سه ستونِ تعداد دریافتی / پرداختی / ماندهٔ تعداد هم اضافه میشود.
- سرِ جدول و ردیف جمع دوره هنگام اسکرول میچسبند.
- کلیک روی هر ردیف، سند آن را باز میکند تا همانجا ویرایشش کنی.
- ردیفهای متهم با یک نوارِ قرمز و نشانِ «• مشکوک» علامت میخورند.
#راههای ورود به این صفحه
- مستقیم از منو: انبار و دارایی → گردش موجودی.
- از کالا و انبار → موجودی اجناس: آیکونِ نمودار روی هر ردیف، همان جنس را باز میکند.
- از کالا و انبار → آبشده و متفرقه و از دفتر ذوب: همان آیکون، روی قبضهای ذوب.
#دو نکته که اشتباه گرفته میشوند
- عیار شخصی موجودی را تکان نمیدهد. اگر متفرقهٔ ۷۴۰ را با عیار شخصیِ ۷۵۰ فروخته باشی، در حساب مشتری ۷۵۰ مینشیند ولی در کاردکس همان ۷۴۰ فیزیکی حرکت میکند — چون از انبار همان جنس بیرون رفته، نه بیشتر. توضیح کامل در بخش ۲۴.
- عیار، هویتِ قلم است. «آبشده آسیا ع۷۴۰» و «آبشده آسیا ع۷۵۰» دو قلم جدا شمرده میشوند تا موجودیشان قاطی نشود. اگر خواستی با هم ببینی، هر دو را تیک بزن.
#فرقش با «ریز ورود و خروج»
هر دو یک سؤال را جواب میدهند ولی در دو مقیاس:
| ریز ورود و خروج | گردش موجودی | |
|---|---|---|
| دامنه | یک سند | یک یا چند قلم، در طول زمان |
| کِی | سرِ ثبت، قبل از ذخیره | بعداً، سرِ انبارگردانی |
| جواب میدهد به | «این سند را درست نوشتم؟» | «موجودیِ این قلم کجا خراب شد؟» |
هر دو از یک موتور جهت (تشخیص ردیف) تغذیه میشوند، پس هیچوقت دو عددِ متناقض نمیدهند.
#۲۸. دفتر چک: چک شخصی و دریافتی
منو → مالی → دفتر چک.
#مسئله
چکی که خودت میکِشی، یک بدهیِ تاریخدار است. تا روزِ سررسید هیچ اتفاقی در حسابت نمیافتد، ولی آن روز باید پول در حساب باشد وگرنه چکِ برگشتی داری. مشکل این است که این تعهد جایی ثبت نمیشود مگر خودت یادداشت کنی، و یادداشتِ کاغذی هم گم میشود.
دفتر چک این را حل میکند: هر چکی که در یک سند بنویسی، خودکار وارد دفتر میشود و تا روزِ پاس شدن آنجا میماند.
#چک کجا ثبت میشود؟
جدولِ جدایی برای چک وجود ندارد؛ چک یک ردیفِ خودِ سند است:
- در سند، یک ردیف با نوعِ ریالی بساز.
- در ستون «شرح»، کدِ ۶ چک را انتخاب کن.
- بلافاصله یک نوارِ آبی زیر همان ردیف باز میشود: نوع | سررسید | شمارهٔ چک | بانک.
- مبلغ را در ستونِ همیشگیِ «فی» مینویسی — نه در نوارِ چک.
چرا مبلغ فیلد جدا ندارد؟ چون آنوقت دو عدد میشد که میتوانستند با هم نخوانند: یکی در سند، یکی در دفتر چک. اینجا فقط یک عدد وجود دارد و هر دو جا همان را نشان میدهند.
نوع خودکار حدس زده میشود و لازم نیست دست بزنی:
| اگر چک در سندی باشد که… | نوعِ پیشفرض | یعنی |
|---|---|---|
| پول از تو بیرون میرود (پرداخت، خرید) | شخصی | چکِ خودت، از دستهچکِ خودت |
| پول به تو میرسد (دریافت، فروش) | دریافتی | چکِ دیگران، در دستِ تو |
اگر مورد استثنایی داشتی (مثلاً برگشتِ یک پرداخت)، خودت از همان نوار عوضش کن؛ انتخابِ دستی همیشه بر حدسِ خودکار مقدم است.
میانبر: روی فیلدِ سررسید کلید * را بزن تا تاریخ امروز بیفتد، بعد اصلاحش کن. (همان میانبرِ آشنای برنامههای حسابداری.)
بانک: فیلدِ بانک از فهرستِ حسابهای بانکیِ خودت تکمیل میشود. اگر از فهرست انتخاب کنی، از آن به بعد موجودیِ همان حساب هم کنترل میشود؛ اگر متنِ آزاد بنویسی، چک ثبت میشود ولی موجودی سنجیده نمیشود.
حسابِ دستهچک را جدا بساز. اگر بانک برایت دستهچک صادر کرده، آن حساب را در حساب بانکی یک حسابِ مستقل بساز — حتی اگر در همان بانکی است که حسابهای دیگر داری. موجودیِ این حساب باید فقط پاسخگویِ چکها باشد. حسابِ شخصی و غیرمرتبط با مغازه اصلاً در این دفتر جایی ندارد.
#صفحهٔ دفتر چک
پنج کارتِ بالا:
| کارت | چه میگوید |
|---|---|
| چکِ شخصیِ پاسنشده | جمعِ تعهداتِ آیندهات — پولی که باید جور کنی |
| چکِ دریافتیِ دستِ ما | چکهایی که گرفتهای و هنوز به هیچ حسابی نخواباندهای |
| در راهِ وصول | چکهایی که خواباندهای و منتظرِ وصولی — هنوز جزوِ موجودیِ بانک نیست |
| راسِ چکهای شخصی | میانگینِ وزنیِ سررسید (زیر توضیح داده شده) |
| در محدودهٔ هشدار | چند فقره همین حالا نیاز به توجه دارند |
زیرِ کارتها دو تابلوی یادآوری هست که فقط وقتی چیزی هست دیده میشوند: «چکهای قابل وصول» (سررسیدشان رسیده و هنوز دستِ توست) و «سررسیدِ چکِ در حساب» (خواباندهای، امروز باید پولش بنشیند). هر ردیف دکمهٔ عملِ خودش را دارد، پس لازم نیست در جدول دنبالشان بگردی.
پالایهها: جستوجو (شمارهٔ چک، بانک، طرف حساب، بابت) + سه ردیف چیپ: نوع، وضعیت، و بازهٔ سررسید. بازهها برخلاف بقیهٔ گزارشها رو به آیندهاند: «سررسید گذشته»، «تا ۷ روز آینده»، «تا ۳۰ روز آینده».
جدول: # | وضعیت | نوع | مبلغ | سررسید | مهلت | شمارهٔ چک | بانک | طرف حساب | سند
ستونِ مهلت به زبان آدمیزاد میگوید «۵ روز مانده» یا «۹ روز گذشته». پاورقیِ جدول همیشه سه عدد دارد: جمع | راس N روز | تعداد.
با کلیک روی شمارهٔ سند، همان سند برای ویرایش باز میشود.
#«راس» یعنی چه؟
راس، میانگینِ سررسیدهاست ولی وزنی بر حسبِ مبلغ. یعنی: اگر همهٔ این چکها را یک چکِ واحد میکردی، سررسیدش چند روز بعد بود؟
مثال واقعی — چهار چکِ شخصی، امروز ۱۴۰۲/۰۳/۱۰:
| مبلغ (﷼) | سررسید | فاصله |
|---|---|---|
| ۵۰۰٬۰۰۰٬۰۰۰ | ۱۴۰۲/۰۳/۱۰ | ۰ روز |
| ۶۰۰٬۰۰۰٬۰۰۰ | ۱۴۰۲/۰۳/۱۵ | ۵ روز |
| ۲٬۵۰۰٬۰۰۰٬۰۰۰ | ۱۴۰۲/۰۳/۳۰ | ۲۰ روز |
| ۵٬۰۰۰٬۰۰۰٬۰۰۰ | ۱۴۰۲/۰۴/۲۵ | ۴۶ روز |
| جمع ۸٬۶۰۰٬۰۰۰٬۰۰۰ | راس ۳۳ روز |
حساب: (۰٫۵×۰ + ۰٫۶×۵ + ۲٫۵×۲۰ + ۵×۴۶) ÷ ۸٫۶ ≈ ۳۳
دقت کن که میانگینِ سادهٔ روزها ۱۸ میشد. راس ۳۳ است چون چکِ سنگین دیرتر سررسید دارد و وزنِ بیشتری در تصمیمِ نقدینگی دارد.
#هشدارِ متناسب با مبلغ
سه روز قبل برای یک چکِ ۵۰ میلیونی کافی است، ولی برای یک چکِ ۵ میلیاردی فاجعه است. برای همین مهلتِ هشدار ثابت نیست و با مبلغ بزرگ میشود:
مهلت = «به ازای هر X ریال، N روز زودتر»
در تنظیمات دو عدد را میگذاری: «هشدار سررسید چک (روز)» و «به ازای هر مبلغ (﷼)». مثلاً با ۱ روز به ازای هر ۵۰۰٬۰۰۰٬۰۰۰ ﷼:
| مبلغ چک | مهلتِ هشدار |
|---|---|
| ۵۰۰ میلیون | ۱ روز قبل |
| ۲٫۵ میلیارد | ۵ روز قبل |
| ۵ میلیارد | ۱۰ روز قبل |
چکِ کوچک هر روز سر و صدا نمیکند و چکِ سنگین بهموقع خبر میدهد. چکِ سررسیدگذشته همیشه هشدار میگیرد، فارغ از مبلغ. همین هشدارها در داشبورد و دستیار هوشمند هم میآیند.
#پاس کردن چکِ شخصی
روی ردیف که بروی، دکمههای عملِ همان چک ظاهر میشوند. برای چکِ شخصی دکمهٔ «پاس شد» است. قبل از ثبت، پنجرهای موجودیِ حسابِ دستهچک را نشان میدهد:
- اگر موجودی کافی است → سبز، ثبت کن.
- اگر کم است → قرمز، و دقیقاً میگوید چقدر کم میآید. جلوی کار را نمیگیرد؛ یا اول با یک حواله حساب را پر میکنی، یا همین حالا ثبت میکنی و سرِ فرصت حساب را جور میکنی.
با ثبتِ پاس شدن:
- وضعیتِ چک به پاس شده میرود و ردیفش در دفتر کمرنگ میشود.
- یک سندِ بانکی خودکار ساخته میشود روی همان حسابِ دستهچک، با شرحِ «پاس شدن چک شخصی …». از این لحظه است که موجودیِ بانک کم میشود — نه لحظهٔ کشیدنِ چک.
چرا دو سند؟ سندِ اولیه حسابِ طرف حساب را تسویه میکند (بدهیات به آبشدهفروش صفر شد). سندِ دوم حسابِ بانک را جابهجا میکند (پول واقعاً از حساب رفت). این دو اتفاق در دو تاریخِ متفاوت میافتند و باید جدا ثبت شوند. اگر خودِ سندِ اولیه از اول روی همان حسابِ بانکی نشسته باشد، سندِ دوم ساخته نمیشود تا مبلغ دو بار کسر نشود.
دکمهٔ «برگشت خورد» وضعیت را برگشتی میکند (هشدارِ فوریِ داشبورد). دکمهٔ «بازگردانی» روی چکهای بستهشده، وضعیت را به «پاس نشده» برمیگرداند و سندِ بانکیِ خودکار را هم حذف میکند.
#گردشِ چکِ دریافتی
چکی که از مشتری میگیری یکشبه نقد نمیشود؛ یک مسیر دارد. دفتر چک همین مسیر را دنبال میکند: چک از دریافت تا وصول چند وضعیت عوض میکند و هر وضعیت دکمههای خودش را نشان میدهد.
مسیرِ عادی:
در جریان (چک دستِ توست) → در حساب (خواباندی) → پاس شده (وصول شد)
و دو مسیرِ جایگزین که بهجای انتظار انتخاب میشوند:
در جریان → نقد شده (تنزیل کردی) • در جریان → خرج شده (به دیگری دادی)
شش وضعیت:
| وضعیت | یعنی | دکمههای موجود |
|---|---|---|
| در جریان | چک دستِ توست، هنوز کاری نکردهای | به حساب بخوابد • نقد شود • خرج شود • برگشت خورد |
| در حساب | به یک حسابِ بانکی خواباندهای، منتظرِ وصول | وصول شد • برگشت خورد • برداشته شود |
| پاس شده | پول در حساب نشست | بازگردانی |
| نقد شده | با تنزیل نقدش کردی | بازگردانی |
| خرج شده | به شخصِ دیگری پشتنویسی کردی | بازگردانی |
| برگشتی | برگشت خورد | دوباره به حساب • بازگردانی |
#به حساب بخوابد
حساب را انتخاب میکنی و تاریخِ خواباندن را میزنی. هیچ سندی ساخته نمیشود، چون هنوز هیچ پولی جابهجا نشده — فقط چک از جیبِ تو به باجهٔ بانک رفته. تنها اثرش این است که مبلغ زیرِ همان حساب در صفحهٔ حساب بانکی با رنگِ دیگر نوشته میشود: «چکِ در راهِ وصول».
این عدد جزوِ ماندهٔ بانک نیست و نباید باشد. اگر چک برگشت بخورد، آن پول هیچوقت نبوده. ماندهٔ بانک باید همیشه پولی باشد که همین حالا میتوانی خرج کنی.
#وصول شد
با «وصول شد»، یک سندِ دریافت روی همان حسابی ساخته میشود که چک را آنجا خوابانده بودی — نه بانکِ صادرکنندهٔ چک. از این لحظه مبلغ از «در راهِ وصول» به ماندهٔ واقعیِ حساب منتقل میشود.
اگر بعداً «بازگردانی» بزنی، سند حذف میشود و چک به در حساب برمیگردد (نه «در جریان»)، چون هنوز آنجا خوابیده است.
#نقد شود (تنزیل)
وقتی نمیتوانی تا سررسید صبر کنی. صندوق را انتخاب میکنی و مبلغی که واقعاً میگیری را مینویسی؛ پنجره همان لحظه اختلاف را نشان میدهد. با ثبت:
- یک سندِ دریافت به همان صندوق، به اندازهٔ مبلغِ خالص.
- یک هزینهٔ «تنزیل چک» به اندازهٔ اختلاف.
مثلاً چکِ ۱٬۵۰۰٬۰۰۰٬۰۰۰ ریالی که ۱٬۴۷۰٬۰۰۰٬۰۰۰ نقد شود، ۳۰٬۰۰۰٬۰۰۰ هزینه ثبت میکند. اگر این هزینه ثبت نشود، سودِ آن ماه از واقعیت بهتر به نظر میرسد.
#خرج شود
چک را به شخصِ دیگری میدهی. طرف حساب را انتخاب میکنی و یک سندِ پرداخت به نامِ او به اندازهٔ مبلغِ کاملِ چک ساخته میشود — تنزیلی در کار نیست، چون چک را به قیمتِ خودش رد کردهای. حسابِ آن شخص همانجا تسویه میشود.
#برگشت خورد
از هر وضعیتی قابلِ زدن است. چک به برگشتی میرود و در داشبورد هشدار میدهد. از آنجا یا «دوباره به حساب» میزنی (اگر طرف قول داده حساب را پر کند) یا «بازگردانی».
هر عملی که سند ساخته باشد، با بازگردانی سندش هم پاک میشود — از جمله هزینهٔ تنزیل. جایی سندِ یتیم باقی نمیماند.
#نکتهای که اشتباه گرفته میشود
کشیدنِ چک موجودیِ بانک را تکان نمیدهد. خیلیها انتظار دارند تا چک را نوشتند، موجودیِ حسابِ بانکی کم شود. این غلط است: پول تا روزِ پاس شدن در حساب است. اگر آن روز موجودی کم شود، همان روز در سندِ بانکیِ خودکار ثبت میشود. تا آن روز، این تعهد فقط در کارتِ «چکِ شخصیِ پاسنشده» دیده میشود.
هزینهٔ بانکی، چک نیست. کارمزد و هزینهای که بانک کم میکند و چیزی فیزیکی جابهجا نشده، با کدِ شرحِ ۸ (کسر) ثبت میشود — نه با یک چک یا سندِ پرداخت. ببین بخش ۵.
#۲۹. خلاصه وضعیت: چک، زیان و سربهسر
این بخش به یک سؤالِ ساده جواب میدهد: چکی که کشیدهام، وضعیتِ مغازه را چقدر بد کرده؟
#قاعدهٔ بنیادی
چک از لحظهای که کشیده میشود بدهی است، نه از لحظهٔ سررسید. سررسید فقط میگوید پول کِی از حساب میرود. دربارهٔ وجودِ بدهی چیزی نمیگوید.
خیلیها چکِ سهماهه را «فعلاً بیخیال» حساب میکنند و فکر میکنند وضعیت مغازه خوب است. نیست. بدهی همان روزِ اول به وجود آمد؛ فقط پرداختش عقب افتاده. تا وقتی چکِ پاسنشده در هیچ ستونی دیده نشود، خلاصهٔ وضعیت دقیقاً به اندازهٔ همان چک بهتر از واقعیت نشان میدهد.
پس در خلاصه وضعیت، چکِ پاسنشده مثل پولِ نقدِ پرداختشده رفتار میکند.
#دو نوع چک، دو سرنوشتِ کاملاً متفاوت
اینجا نکتهٔ اصلی است. دو نفر هر دو یک چکِ ۵۰۰ میلیونی میکشند، ولی وضعیتشان زمین تا آسمان فرق دارد:
| چک را بابتِ چه کشیدی؟ | چه چیزی وارد مغازه شد؟ | نتیجه |
|---|---|---|
| کالا / طلا (سند ردیفِ غیرریالی دارد) | جنس آمد و در انبار نشست | سربهسر — بدهی زیاد شد، ولی دارایی هم به همان اندازه زیاد شد |
| هزینه (سند تماماً ریالی است) | هیچچیز | زیانِ خالص — بدهی زیاد شد و چیزی در برابرش نیامد |
همین یک تمایز، تفاوتِ «زیان» و «سربهسر» را میسازد. پنل خودش تشخیص میدهد: اگر سندی که چک در آن کشیده شده حتی یک ردیفِ غیرریالی داشته باشد (طلا، کالا، سکه)، آن چک «در برابرِ کالا» حساب میشود.
#چهار کارتِ بالای خلاصه وضعیت
وقتی چکِ پاسنشده داشته باشی، پنلِ خلاصه وضعیت یک بخش با این کارتها نشان میدهد:
| کارت | معنی |
|---|---|
| 🔴 هزینهٔ خالص — بدون معادل | چکهای شخصیِ بابتِ هزینه. این عدد مستقیم از وضعیتت کم شده است. |
| 🟢 در برابرِ کالا — سربهسر | چکهای شخصیِ بابتِ جنس. جنسش در انبار است؛ نه سود، نه زیان. |
| 🔵 چک دریافتی — طلب | چکهایی که از دیگران گرفتهای و هنوز پاس نشده. طلبِ توست. |
| 🟡 چک برگشتی دریافتی | چکی که گرفتی و خورد. دارایی حساب نمیشود — وصول نشده. |
هر کارت زیرِ مبلغِ ریالی، معادلِ گرم ۷۵۰ را هم مینویسد؛ چون در کارِ طلا عددِ ریالی بهتنهایی حرفی نمیزند.
عدمتقارنِ عمدی: چکِ شخصیِ برگشتی همچنان بدهی است (پول را هنوز ندادهای)، ولی چکِ دریافتیِ برگشتی دارایی نیست. ترازِ سادهانگارانه دقیقاً همینجا اشتباه میکند و وضعیت را دو برابر بهتر از واقع نشان میدهد.
#دو مثال واقعی
مثال ۱ — چکِ هزینه: مظنه ۱۱۱٬۷۵۰٬۰۰۰ تومان است و انبار خالی. یک چکِ ۵۰۰ میلیون تومانی بابتِ هزینه میکشی.
- وضعیت ریالی: −۵۰۰٬۰۰۰٬۰۰۰
- وضعیت طلایی: −۱۹٫۳۸ گرم ۷۵۰
هیچچیز در برابرش نیامده. این عدد، عددِ زیان است.
مثال ۲ — چکِ کالا: مظنه ۱۱۱٬۸۶۰٬۰۰۰ تومان. ۱۵۰ گرمِ ۷۵۰ آبشده خریدهای و در انبار است، و در برابرش چکِ ۳٬۸۷۳٬۴۴۷٬۰۰۰ ریالی کشیدهای.
- وضعیت ریالی: +۳٬۴۴۷٬۰۰۰
- وضعیت طلایی: +۰٫۱۳ گرم ۷۵۰
عملاً صفر. بدهی بزرگ است ولی معادلش در انبار خوابیده — سربهسر. اینجا نه سود کردهای نه زیان.
#چرا معادلِ گرم؟
مظنه قیمتِ یک مثقال (۴٫۶۰۸۳ گرم) طلای عیار ۷۰۵ است. برای رسیدن به قیمتِ یک گرمِ ۷۵۰:
قیمت گرم ۷۵۰ = مظنه ÷ ۴٫۶۰۸۳ × ۷۵۰ ÷ ۷۰۵ = مظنه ÷ ۴٫۳۳۱۸
با همین یک تقسیم، هر عددِ ریالی به زبانِ طلا ترجمه میشود. در کارِ طلا این تنها زبانی است که معنی دارد: «امسال ۵۰۰ میلیون ضرر کردم» مبهم است، ولی «۱۹ گرم عقب افتادم» دقیق است.
#ارتباط با دفتر چک
انتهای این بخش لینکِ «رفتن به دفتر چک» هست. برای ثبت، سررسید، پاس کردن و برگشت زدنِ چک ببین بخش ۲۸. چکِ پاسشده در این کارتها نمیآید — چون سندِ بانکیِ خودش را ساخته و اثرش قبلاً در موجودیِ بانک دیده شده است. دوباره شمردنش یعنی دو بار کسر.
#۳۰. کالای غیرطلایی: جنسی که قیمت طلا رویش اثر ندارد
بعضی جنسها در مغازهٔ طلا هستند ولی طلا نیستند. آیفونِ روکشطلا، حلقهٔ پلاتین، انگشترِ نقره، ساعتِ آبکاریشده. اسمشان طلاست، براقیشان طلاست، ولی قیمتِ طلا هیچ اثری روی قیمتشان ندارد.
قاعدهٔ بنیادی: جنسی که طلا نیست، هرچقدر هم سنگین باشد، وزنِ ۷۵۰ِ آن صفر است — نه تقریباً صفر، دقیقاً صفر.
چرا اینقدر مهم است؟ چون اگر یک حلقهٔ پلاتینِ ۳۸ گرمی را ردیفِ طلا ثبت کنی، ماندهی طلاییِ طرف حساب ۳۸ گرم دروغ میگوید. فردا که مظنه بالا برود، سامانه فکر میکند ۳۸ گرم طلای گرانشده داری — در حالی که آن پلاتین با بالا رفتنِ مظنه یک ریال هم گران نشده است.
#چطور یک کالای غیرطلایی تعریف کنم
در فرمِ تعریف جنس (که از داخل سند هم باز میشود، وقتی نامی مینویسی که در کاتالوگ نیست):
| فیلد | چه بگذاری |
|---|---|
| نوع کالا | «کالای غیرطلایی» — همین یک انتخاب تمامِ رفتار را عوض میکند |
| محاسبهٔ فی | عددی (هر دانه) یا وزنی (هر گرم) |
| ارز دریافت | ریال، تومان، دلار یا هر ارزی که تعریف کردهای |
| فی نقدی | قیمتِ پیشفرض، تا موقعِ ثبتِ سند خودش بیاید |
از این به بعد هر جا آن نام را در سند بنویسی، ردیف خودش به کالای غیرطلایی تبدیل میشود، ستونِ عیارش «بدون عیار» میشود و ستونِ وزنِ ۷۵۰ روی ۰٫۰۰۰ گ قفل میماند.
#عددی یا وزنی؟
این دو حالت با یک دکمهٔ کوچک کنارِ نامِ ردیف عوض میشوند و همه چیزِ محاسبه به آن بستگی دارد:
| مبنا | فی یعنی | فرمول | مثالِ واقعی |
|---|---|---|---|
| عددی | قیمتِ هر دانه | تعداد × فی | ۲ عدد آیفون × ۱۳۰۰ دلار = ۲۶۰۰ دلار |
| وزنی | قیمتِ هر گرم | وزن × فی | ۳۸٫۶۱ گرم پلاتین × ۱۸٬۰۰۰٬۰۰۰ = ۶۹۴٬۹۸۰٬۰۰۰ ریال |
- عددی برای جنسهایی که وزنشان بیربط است: گوشی، ساعت، جعبه، سنگ.
- وزنی برای جنسهایی که گرمی معامله میشوند ولی طلا نیستند: پلاتین، نقره، پالادیوم.
در حالتِ عددی، ستونِ وزن کمرنگ میشود (میتوانی وزنِ فیزیکی را برای انبارگردانی بنویسی ولی در قیمت اثر ندارد). در حالتِ وزنی، ستونِ تعداد کمرنگ میشود.
#وقتی جنس را به دلار میخری
آقای اکبری دو آیفون به تو میدهد، دانهای ۱۳۰۰ دلار. اگر این ۲۶۰۰ دلار را با نرخِ امروز به ریال تبدیل کنی، فردا که دلار تکان بخورد بدهیِ ثابتِ تو عددِ دیگری میشود — در حالی که تو هنوز دقیقاً همان ۲۶۰۰ دلار بدهکاری.
برای همین سامانه ارز را تبدیل نمیکند؛ به آن ستونِ خودش را میدهد:
- در پاورقی سند، کنارِ «جمع طلا» و «جمع ریال»، خطِ «جمع دلار: ۲٬۶۰۰» میآید.
- در ماندهٔ طرف حساب، کنارِ ماندهٔ طلایی و ریالی، یک کارتِ دلار اضافه میشود.
- تومان و ریال استثنا هستند: تومان همان ریال است و با ضریبِ ۱۰ در ستونِ ریالی مینشیند.
تنها جایی که ارز به ریال تبدیل میشود، «خلاصه وضعیت» است — آنجا سؤال این است که «این دارایی امروز چقدر میارزد»، نه «چقدر بدهکارم».
#در گزارش موجودی چه میبینی
کالای غیرطلایی از موجودیِ طلا جدا گزارش میشود. در خلاصه وضعیت پنلی با دو کارت داری:
| کارت | چه میگوید |
|---|---|
| ارزش موجودی | این جنسها امروز روی هم چقدر میارزند (ارزها با نرخ روز) |
| اثر بر حساب طلایی | همیشه ۰٫۰۰۰ گ۷۵۰ — یادآوریِ صریحِ همان قاعده |
زیرش جدولِ شش قلمِ گرانترت میآید با تعداد، وزنِ فیزیکی و ارزش. در جدولِ «موجودی فیزیکی» هم یک خطِ جدا به نامِ «موجودی کالای غیرطلایی» اضافه شده است.
#فروختنش
فرقی با خرید ندارد، فقط جهت برعکس میشود. سامانه هنگام فروش فیِ دریافتیِ خودت را نشان میدهد — یعنی این جنس با چه قیمتی پای تو افتاده — تا بدانی از کجا به بالا سود میکنی:
- آیفونی که ۱۳۰۰ دلار خریدی، اگر دلار امروز ۳۵٬۱۴۴ تومان باشد، پای تو ۴۵٬۶۸۸٬۰۰۰ تومان افتاده. آن را ۵۰ میلیون بفروشی، سودت مشخص است.
- پلاتینی که گرمی ۱۸ میلیون خریدی، گرمی ۲۰ میلیون بفروشی، همان اختلاف سودِ توست.
در هر دو حالت قیمتِ طلا اصلاً وارد محاسبه نمیشود — نه در خرید، نه در فروش، نه در مانده.
#اشتباهِ رایج
جنس را «کالای غیرطلایی» تعریف نکردهای و پلاتین را ردیفِ طلا با عیارِ ۷۵۰ زدهای.
نشانهاش این است که ماندهٔ طلاییِ طرف حساب بیدلیل سنگین است و موجودیِ طلای مغازه با ترازو نمیخواند. راهحل: جنس را در کاتالوگ «کالای غیرطلایی» کن، بعد در سند نامش را دوباره انتخاب کن — ردیف خودش اصلاح میشود و عیارش پاک میگردد.
#۳۱. اصلاح موجودی: وقتی دفتر با ترازو نمیخواند
صفحهٔ موجودی → سربرگ «اجناس» یا «آبشده و متفرقه». همچنین از صفحهٔ گردش موجودی، وقتی اختلاف پیدا شد.
#چرا اصلاً اختلاف پیدا میشود
صد گرم زنجیر از کارخانه میگیری و ریزریز میفروشی. جمعِ آن ریزفروشها با صد گرم مو میزند و ته دفتر ۰٫۰۳ گرم میماند که در صندوق وجود ندارد. این دزدی نیست، اختلافِ ترازو است — ولی تا سند نخورد، ضرر هم نیست و هیچ گزارشی نشانش نمیدهد.
حالتِ دومِ رایجتر: هنگام فروش، «کارتیه» را انتخاب کردهای در حالی که جنسِ واقعی «دستبند کارتیه» بوده. حالا دفتر میگوید ۱۴۳ گرم کارتیه داری که در ویترین نیست، و دستبند کارتیهای که داری در دفتر نیست.
قاعدهای که این بخش نگهبانش است: موجودیِ اشتباه هیچوقت دستی پاک نمیشود. هر بار عددِ دفتر را به عددِ ترازو میرسانی، باید سندی پشتش بماند که بگوید چه چیزی، چقدر و چرا خارج شد.
اگر عددِ ستونِ «وزن» را دستی بازنویسی کنی، موجودی عوض میشود ولی دفتر اسناد عوض نمیشود. آنوقت این دو برای همیشه از هم دور میافتند و طلایی که گم شده هیچجا بهعنوان ضرر شناسایی نمیشود.
#کارِ عملی
هر ردیفِ موجودی حالا یک چکباکس در ابتدای سطر و یک دکمهٔ مداد در انتهای سطر دارد.
- دکمهٔ مداد را بزن (یا ردیف را تیک بزن و از نوارِ بالا «اصلاح موجودی» را بزن).
- پنجرهٔ «میخواهم بشود» باز میشود: بالا وضعِ فعلی را میبینی، پایین عددی که میخواهی به آن برسد.
- وزن (و برای اجناس، تعداد) را بنویس — یا دکمهٔ «صفرش کن» را بزن.
- همان لحظه، پایینِ پنجره ببین چه سندی قرار است ساخته شود و ماندهٔ سند چقدر است.
- «ثبت اصلاح» را بزن.
برای چند قلم با هم: چندتا را تیک بزن و از نوارِ بالا «صفر کردن موجودی» را بزن؛ همه در یک سند صفر میشوند و جمعِ ضرر را قبل از تأیید میبینی.
#ماندهٔ سند: مهمترین عدد این پنجره
سه حالت با سه نتیجهٔ اقتصادیِ کاملاً متفاوت:
| کاری که میکنی | ماندهٔ سند | یعنی چه |
|---|---|---|
| صفر کردن بدون مقصد | منفی، به اندازهٔ کلِ معادل | تمامِ آن وزن ضررِ توست |
| انتقال به جنسی با همان اجرت٪ | دقیقاً ۰ | فقط برچسبِ جنس عوض شد، نه طلایش |
| انتقال به جنسی با اجرتِ متفاوت | دقیقاً همان تفاوتِ اجرت | نه یک ریال بیشتر، نه کمتر |
برای انتقال، در همان پنجره تیکِ «این مقدار اشتباهی از این جنس کم شده — به جنسِ دیگری منتقل شود» را بزن و مقصد را انتخاب کن. هرچه از این ردیف کم شود، عیناً به مقصد اضافه میشود؛ طلا جایی نمیرود.
#«معادل ۷۵۰» چرا اجرت را هم میشمارد
اگر ۱۴۳٫۶۵ گرمِ کارتیه با اجرت ۱۲٪ بسوزد، فقط طلایش نسوخته — اجرتی هم که بابتش پول دادهای با آن سوخته است:
۱۴۳٫۶۵ × (۷۵۰ ÷ ۷۵۰) × (۱ + ۰٫۱۲) = ۱۶۰٫۸۹ گ۷۵۰
به همین دلیل انتقالِ بینِ دو جنسِ هماجرت ماندهٔ صفرِ دقیق میدهد، ولی انتقال از ۱۵٪ به ۱۲٪ روی ۱۰۰ گرم دقیقاً ۳ گرم ماندهٔ منفی میسازد.
این عدد فقط گزارشی است. خودِ موجودی و کاردکس همچنان با وزنِ فیزیکی کار میکنند، وگرنه اجرت به عیارِ طلا قاطی میشد و «سود عیار» دروغ میگفت.
#سندی که ساخته میشود
- نوعش «سایر» است تا در گزارش خرید و فروش شمرده نشود.
- طرف حسابش «حساب داخلی — بررسی و اصلاح موجودی» است، نه یک آدمِ واقعی.
- تشخیصِ ردیفها مطلق است: «خروج» یا «ورود».
- فی خالی است — اصلاح موجودی هیچ پولی جابهجا نمیکند و هیچ بدهی و طلبی نمیسازد.
- در یادداشتِ هر ردیف نوشته میشود «از فلان به فلان گرم».
#لغو کردن
زیر جدولِ موجودی، «اصلاحهای اخیرِ موجودی» با شمارهٔ سند، تاریخ، اقلام و ماندهٔ هر کدام میآید. دکمهٔ «لغو» سند را پاک میکند و موجودی را موبهمو به عددِ قبل برمیگرداند — حتی اگر بعداً خودِ آن ردیف را از موجودی حذف کرده باشی (ردیف دوباره ساخته میشود).
#مسیرِ کوتاه از کاردکس
جایی که اختلاف کشف میشود صفحهٔ «گردش موجودی» است. حالا همانجا هم درست میشود: وقتی وزنِ ترازو را وارد کردی و اختلاف ماند، زیر جعبهٔ تطبیق یک دکمهٔ «اصلاح موجودی» میآید که همان پنجره را با عددِ ترازو از پیش پُرشده باز میکند.
#کجا در گزارشها دیده میشود
در خلاصه وضعیت کارتی به نام «اصلاح موجودی» اضافه شده که میگوید تا امروز روی هم چقدر طلا بابتِ اختلافِ ترازو سوخته است. این عدد در هیچ گزارشِ دیگری دیده نمیشود — چون نه فروش است، نه خرید.
#تغییر نام، بایگانی و تفکیک جنسها (v111)
در کالا و انبار ← موجودی اجناس، دکمهٔ «مدیریت جنسها» فهرست کامل اطلاعات پایه را باز میکند. بالای پنجره میتوانید نام، گروه یا سازنده را جستوجو و فهرست را میان «همه»، «نمایشی» و «بایگانی» محدود کنید.
سه کار از هم جدا هستند:
| کار | نتیجه |
|---|---|
| ویرایش نام | نامِ فهرست و ردیف جاری انبار عوض میشود؛ فاکتورها و اسناد قبلی با نام زمان ثبت دستنخورده میمانند. |
| بایگانی | جنس از پیشنهادهای سند تازه، پیشفاکتور و اسکن بارکد کنار میرود؛ سابقه، کاردکس و موجودی حذف نمیشود و هر زمان قابل بازگردانی است. |
| حذف | فقط وقتی مجاز است که جنس هیچ سند، موجودی و لیبل فعالی نداشته باشد. جنس استفادهشده باید بایگانی شود، نه حذف. |
اگر جنس بایگانیشده را اشتباهی دستی در سند بنویسید یا بارکدش را اسکن کنید، سامانه ثبت را متوقف میکند و مسیر بازگردانی از «مدیریت جنسها» را نشان میدهد.
#تفکیک یک نام کلی به چند جنس دقیق
اگر قبلاً چند مدل را با یک عنوان مثل «خردهریز لوکس» ثبت کردهاید و حالا میخواهید «نیمست پروانه» و «دستبند آنجلا» جدا باشند:
- مقصدها را با «تعریف جنس جدید» بسازید و عیار و اجرت هرکدام را درست وارد کنید.
- کنار ردیف عنوان کلی، دکمهٔ قیچی (تفکیک) را بزنید.
- وزن و تعداد انتقالی هر مقصد را وارد کنید. جمع وزن باید دقیقاً با موجودی مبدأ برابر باشد؛ اگر مبدأ تعداد دارد، جمع تعداد هم باید برابر باشد.
- پیش از ثبت، ماندهٔ سند را ببینید. اجرتهای یکسان ماندهٔ صفر میدهند؛ تفاوت عیار یا اجرت دقیقاً بهعنوان اختلاف همان سند نمایش داده میشود.
- «ثبت تفکیک» را بزنید. یک سند رسمی بررسی و اصلاح موجودی ساخته میشود: مبدأ صفر و مقصدها به همان مقدار زیاد میشوند.
- پس از کنترل کاردکس، عنوان کلی را از مدیریت جنسها بایگانی کنید.
این روش فاکتورهای قدیمی را بازنویسی نمیکند، طلا را بیسند جابهجا نمیکند و امکان لغو سند اصلاح را هم حفظ میکند.
#خدمتِ وزنی، تعدادی و ارزی (v107)
برای حملونقل، بستهبندی یا هر خدمتی که چیزی به ویترین اضافه نمیکند، در سند نوع ردیف را اجرت/خدمات بگذارید و دکمهٔ خدمت را بزنید. خدمت سه جزء دارد:
- مبنای محاسبه: هر گرم یا هر خدمت/تعداد؛
- فی خدمت: مبلغ هر واحد؛
- واحد فی: تومان، دلار یا ارز ثبتشدهٔ دیگر.
برای ارز غیرریالی، نرخ تبدیل همان معامله ذخیره میشود تا تغییر نرخ آنلاین سابقهٔ سند را عوض نکند. مبلغ ریالی با فرمول مقدار × فی × نرخ تبدیل محاسبه میشود؛ در صورت نبودن نرخ معتبر، ارز در ستون مستقل خودش میماند.
ثبت خدمت هیچ وزن، موجودی فیزیکی یا طلای ۷۵۰ به حساب اضافه نمیکند. فقط ماندهٔ ریالی یا ارزی طرف حساب را تغییر میدهد. در گزارش کارکرد، پرداخت خدمت سود و دریافت خدمت زیان محسوب میشود؛ مشابه مسیر کد ۸، اما با شرح و مبنای روشنتر. پیش از ثبت، واحد، مقدار، فی و نرخ تبدیل را کنترل کنید.
#بستن سهم شرکا و تبدیل طلب ریالی به طلا (v108)
در نوع حسابها ← سرمایه و برداشت، گزارش سهم شرکا حالا دو استخر واقعی و مستقل را نشان میدهد:
- استخر طلا: طلای فیزیکی و ماندهٔ خالص طلایی حسابها، بر حسب گرم ۷۵۰؛
- استخر ریال: نقد، چک، داراییهای ریالی و ماندهٔ خالص ریالی حسابها، بدون اینکه ارزش همان طلا دوباره به آن اضافه شود.
عدد «معادل کل وضعیت بر حسب طلا» فقط برای ارزشگذاری روز است. این عدد همراه با استخر ریال تقسیم نمیشود، چون در آن صورت یک دارایی دو بار بین شرکا توزیع خواهد شد.
#ثبت نهایی سهمها
- درصد همهٔ شرکا را کنترل کنید؛ مجموع باید دقیقاً ۱۰۰٪ باشد.
- برداشت و آوردهٔ هر شریک را در کارت خودش بازبینی کنید.
- دکمهٔ «بستن و ثبت سهمها» را بزنید.
- پنجرهٔ پیشنمایش، سهم ناخالص طلا و ریال و ماندهٔ خالص پس از برداشت را برای هر شریک نشان میدهد.
- تاریخ و یادداشت را ثبت و عملیات را تأیید کنید.
برای هر شریک، سندی روی همان حساب سرمایه و برداشت ساخته میشود. سهم ناخالص ثبت میشود تا برداشتهای قبلی در خود حساب تهاتر شوند و ماندهٔ نهایی، طلب یا بدهی واقعی شریک باشد. ردیف آخر تتمهٔ گردکردن را میگیرد؛ بنابراین جمع اسناد دقیقاً با استخر برابر میماند. هر نوبت فقط وقتی قابل ثبت است که استخر جاری طلا یا ریال مانده داشته باشد؛ ثبت نوبت، همان استخر را صفر میکند و از دوبارهکاری جلوگیری میشود.
این اسناد حسابداریاند و هیچ طلا یا پول فیزیکی را وارد یا خارج نمیکنند؛ به همین دلیل در گردش موجودی و کاردکس نمایش داده نمیشوند.
#طلاییکردن طلب ریالی شریک
اگر ماندهٔ حساب سرمایه نشان دهد شریک از مغازه طلب ریالی دارد، در کارت او دکمهٔ «تبدیل طلب ریالی به طلا» دیده میشود:
- مبلغ تبدیل را تا سقف طلب فعلی وارد کنید.
- نرخ هر گرم ۷۵۰ را کنترل کنید؛ نرخ روز بهصورت پیشفرض میآید.
- وزن پیشنمایش را بررسی و تبدیل را ثبت کنید.
فرمول تبدیل:
وزن طلب طلایی = مبلغ ریالی ÷ نرخ هر گرم ۷۵۰
نرخ داخل همان سند قفل میشود. سند، طلب ریالی را میبندد و همان ارزش را به طلب طلایی تبدیل میکند، بدون جابهجایی فیزیکی. از این لحظه تغییر نرخ طلا روی ارزش واقعی بدهی مغازه و در نتیجه سود یا زیان آن اثر میگذارد؛ دقیقاً مانند فروش پولی، اما با ثبت شفافِ تبدیل و بدون ساخت حرکت انبار.
#تغییر درصد، ورود یا خروج شریک در میانهٔ دفتر (v109)
درصدهای شراکت فقط برای دورهٔ جاری معتبرند. هر زمان درصد یکی از شرکا عوض میشود، شریک تازهای وارد میشود یا شریکی کنار میرود، این ترتیب را رعایت کنید:
- در نوع حسابها ← سرمایه و برداشت، سهم دورهٔ جاری را با درصدهای فعلی ببندید.
- مطمئن شوید نشان «استخر جاری صفر است» دیده میشود.
- حالا درصدها را ویرایش، شریک تازه را اضافه یا شریک قبلی را حذف کنید؛ مجموع درصدهای دورهٔ بعد باید ۱۰۰٪ شود.
- از اولین گردش بعدی، سود و زیان فقط با ترکیب تازه محاسبه میشود.
پنل اجازه نمیدهد وقتی پس از آخرین تقسیم هنوز استخر باز دارید، درصد یا فهرست شرکا را تغییر دهید. این کنترل مانع میشود سودِ یک بازه با درصدهای بازهٔ بعد تقسیم شود. برای اولین راهاندازی، تا پیش از ثبت نخستین تقسیم میتوانید فهرست و درصدها را کامل کنید.
هر تقسیم در تاریخچهٔ نوبتها با تاریخ، استخر طلا، استخر ریال و درصد همان زمان ذخیره میشود؛ بنابراین تغییر درصد امروز، سابقهٔ دورههای بستهشده را بازنویسی نمیکند. اگر بعد از آخرین تقسیم هیچ گردش تازهای ثبت نشده باشد، دکمهٔ «لغو آخرین تقسیم» اسناد همان نوبت را حذف و درصدهای پیش از آن را برمیگرداند. پس از ثبت گردش جدید، لغو خودکار برای حفظ تاریخچه مسدود است.
بستن دفتر مالی برای هر سال همچنان روش پیشنهادی است، اما برای تغییر شریک در میانهٔ سال اجباری نیست. ابتدا دوره را تقسیم و صفر کنید، سپس ترکیب شراکت را عوض کنید. حتی اگر تنها مالک هستید، خودتان را با سهم ۱۰۰٪ ثبت کنید و در پایان دوره تقسیم را انجام دهید تا سود دورهٔ تازه از صفر شروع شود.
آورده و برداشت شریک سود یا زیان مغازه نیست. آورده روی حساب سرمایه به نام همان شریک ثبت میشود و با دارایی واردشده خنثی است؛ برداشت نیز فقط ماندهٔ همان شریک را تغییر میدهد. در تقسیم بعدی، فقط برداشت و آوردهای محاسبه میشود که پس از آخرین نوبت ثبت شده باشد.
#۳۳. خدماتِ بدون جابهجایی فیزیکی
ویدئوی آموزشی نسخهٔ v107 همین مسیر را نشان میدهد: کارمزد حملِ طلای دریافتی را نباید دوباره بهعنوان طلای بدهکار ثبت کرد. اگر خدمت به ازای گرم یا تعداد انجام شده، ردیف اجرت/خدمات بسازید؛ این ردیف وزن طلای مغازه را تغییر نمیدهد و فقط هزینه یا طلب خدمت را ثبت میکند. برای خدمات دلاری نیز ارز و نرخ همان سند ذخیره میشود و در گزارشها با واحد خودش قابل پیگیری است.
مرز حسابداری: خدمت، کالا نیست؛ چیزی به ویترین وارد یا از آن خارج نمیشود. بنابراین برای ثبت آن از ردیف طلا استفاده نکنید.
حذف، ردیف را از موجودی برمیدارد ولی هیچ سندی نمیسازد؛ یعنی همان بیصدا گمشدنِ طلا. اگر موجودیِ چیزی تمام شده، صفرش کن — نه حذفش.
#۳۲. تعمیرات و آبکاری: جنسی که فروخته نشده، فقط بیرون رفته
انگشترِ مشتری را میدهی دستِ تعمیرکار تا آبکاری شود. چند روز بعد برمیگردد. در این فاصله هیچ معاملهای نشده — نه فروختی، نه خریدی. جنس فقط امانت دستِ کسی است.
اگر این حرکت را با سندِ معمولیِ فروش/خرید (یا دریافت/پرداختِ ساده) ثبت کنی، دفتر درست میماند ولی گزارشِ کارکرد دروغ میگوید: روزی که جنس بیرون میرود یک زیانِ سنگین ثبت میشود و روزی که برمیگردد همانقدر سود. هر دو خیالیاند و بینِ این دو روز، گزارشِ سود و زیانِ مغازه بهاندازهٔ کلِ ارزشِ آن جنس غلط است.
صفحهٔ «تعمیرات و آبکاری» در منوی کناری برای همین ساخته شده.
#چطور کار میکند
هر کارِ تعمیر یک سند است، از اول تا آخر. سند بسته نمیشود و سندِ تازه هم نمیخواهد؛ هر اتفاقِ تازه یک ردیف به همان سند اضافه میکند:
| مرحله | دکمه | چه ردیفی ساخته میشود |
|---|---|---|
| جنس را دادی رفت | ارسال به تعمیر | ردیفِ طلا، بیفی، تشخیصِ خالی |
| جنس برگشت | بازگشت | ردیفِ طلا با تشخیصِ مرجوع |
| اجرت را تعمیرکار اعلام کرد | اجرت | ردیفِ ریالی (بدهیِ ما به او) |
| اجرت را پرداخت کردی | پرداخت | ردیفِ ریالیِ مرجوع (بدهی صفر میشود) |
چون همه در یک سنداند، ماندهٔ سند همیشه میگوید بینِ تو و تعمیرکار چه چیزی معلق است.
#تابلوی تعمیرکاران
بالای صفحه سه عدد:
- نزد تعمیرکاران — چند گرم۷۵۰ همین حالا فیزیکاً بیرون است.
- کسریِ برگشتی — چقدر از چیزی که فرستادی، کمتر برگشته. این طلبِ واقعیِ توست.
- اجرتِ پرداختنشده — چقدر بابتِ اجرت به تعمیرکارها بدهکاری.
پایینتر جدولِ کارها با فیلترِ باز / دیرکرد / تمامشده. کاری که بیش از ۷ روز بیرون مانده و برنگشته، نشانِ قرمزِ دیرکرد میگیرد.
#مثالِ کامل
انگشتری ۶٫۳۸ گرم برای آبکاری فرستادی. برگشت ۶٫۳۴ گرم شد و اجرت ۱۵۰ هزار تومان.
ارسال انگشتر آران ۶٫۳۸ گرم
بازگشت انگشتر آران ۶٫۳۴ گرم ← مرجوع
اجرت ۱٬۵۰۰٬۰۰۰ ریال
پرداخت ۱٬۵۰۰٬۰۰۰ ریال ← مرجوع
نتیجه:
- ماندهٔ طلاییِ سند: ۰٫۰۴ گرم به نفعِ تو — تعمیرکار این مقدار کم برگردانده و بدهکارِ توست.
- ماندهٔ ریالی: صفر — اجرت تسویه شده.
- سود و زیان در کارکرد: صفر. این مهمترین عدد است. تعمیر معامله نبوده، پس هیچ سودی نساخته.
آن ۰٫۰۴ گرم زیان نیست، طلب است. تا وقتی تعمیرکار جبرانش نکرده، در ماندهٔ حسابش میماند. اگر بخشیدی یا آب رفته بود، با «اصلاح موجودی» (بخش ۳۱) به ضرر تبدیلش کن — آنجا جای درستش است.
#دو اشتباهی که پنل جلویشان را میگیرد
۱) جنس را با سندِ «دریافتِ» تازه برگرداندی، نه با دکمهٔ «بازگشت».
آنوقت پنل خیال میکند آن انگشتر را خریدهای — یک سودِ خیالی به اندازهٔ کلِ وزنِ جنس در کارکرد ظاهر میشود، و در نرمافزارهایی که نرخِ میانگین دارند، نرخِ دریافتیِ کلِ مغازه هم خراب میشود.
پنل این را میبیند: اگر سندی از نوعِ دریافت با نامِ همان جنس و همان طرفحساب ثبت شود در حالی که کارِ تعمیرِ بازی وجود دارد، بالای صفحهٔ تعمیرات یک جعبهٔ هشدارِ نارنجی میآید و میگوید کدام جنس، چه وزنی و مربوط به کدام کار است. چیزی خودکار پاک نمیشود؛ فقط به تو میگوید.
۲) اجرت را در ستونِ اجرتِ همان ردیفِ طلا نوشتی.
اجرت روی ردیفِ طلا، جهتِ پول را برعکس میکند: بهجای اینکه تو ۱٬۵۰۰٬۰۰۰ ریال به تعمیرکار بدهکار شوی، پنل میگوید او به تو بدهکار است — و یک «سودِ اجرت» هم میسازد که وجود ندارد. اجرت همیشه ردیفِ پولیِ جداست؛ دکمهٔ «اجرت» همین کار را میکند.
پنل اگر روی ردیفِ امانت اجرت یا فی ببیند، همانجا اخطار میدهد.
#اشتباهِ رایج
هر بار که جنس برگشت، یک سندِ جدید میزنی.
سندِ کار را باز نگه دار. تمام رفتوبرگشت و اجرت و پرداختِ یک کار باید در یک سند باشد، وگرنه ماندهٔ آن کار هیچجا یکجا دیده نمیشود.
#۳۳. پوشش ریسک: بستن مظنه و وضعیت باز
ساعت ۱۰ صبح از مشتری ۳۷٫۴۴ گرمِ عیار ۷۴۰ متفرقه میخری. تا لحظهای که همین وزن را به بنکدار نفروختهای، نوسانِ قیمتِ طلا مالِ توست — نه سودِ معامله، بلکه قمارِ بازار. اگر تا عصر مظنه بیفتد، اسپردی که با زحمت روی آن معامله گرفتی دود میشود.
کارِ درست همان چیزی است که بازار به آن میگوید «بستنِ مظنه»: هرچه از مشتری خریدی، همان وزن را فوراً به بنکدار بفروش؛ هرچه به مشتری فروختی، همان وزن را فوراً از بنکدار بخر. آنوقت سودت فقط اسپردِ معامله است و به قیمتِ فردا کاری ندارد.
صفحهٔ «پوشش ریسک» در منوی کناری، این وزنِ باز را لحظهای نشان میدهد.
#سه عددِ بالای صفحه
- وضعیتِ باز — جمعِ جبریِ همهٔ طلاها به گرم۷۵۰. مثبت یعنی طلا داری و منتظرِ فروشی؛ منفی یعنی طلا فروختهای که هنوز نخریدهای. صفر یعنی مظنه بسته است.
- ریسکِ نوسان — همان وزنِ باز، ضربدرِ نرخ روز، ضربدرِ درصدی که خودت انتخاب میکنی (۱٪ / ۲٪ / ۵٪). یعنی «اگر بازار اینقدر تکان بخورد، چند ریال جابهجا میشوم».
- روزهای پوششنشده — چند روز معاملهٔ تکفروشی داشتهای که تهِ روز خالصش صفر نشده.
ماندهٔ طلاییِ افتتاحیهٔ اشخاص هم در وضعیتِ باز حساب میشود؛ آن هم طلای واقعیِ در جریان است.
#روزشمارِ مظنه
جدولِ اصلی، هر روزِ کاری را یک سطر میکند: چقدر تکفروشی (مشتری)، چقدر بنکداری (همکار/بنکدار و ذوبخانه)، چقدر تسویه، و خالصِ روز. خالصِ صفر سبز است، باز بودن رنگی.
روی هر روزِ باز، دکمهٔ «بستنِ مظنه» یک سندِ آماده باز میکند: طرفِ مقابل بنکدار، جهتِ سند عکسِ وضعیتت، وزن دقیقاً همان وزنِ باز، واحدِ قیمت مثقال و شرحِ «آبشده».
فی را پنل نمینویسد — عمداً. مظنه را بازار تعیین میکند نه دفتر. عددِ همان لحظه را خودت میگذاری.
#مثالِ ویدئویی
خرید از مشتری ۳۷٫۴۴ گرم عیار ۷۴۰ → ۳۶٫۹۴۱ گرم۷۵۰ وضعیتِ باز: ۳۶٫۹۴۱
فروش به بنکدار ۳۶٫۹۴۱ گرم۷۵۰ وضعیتِ باز: ۰
بعد از سطرِ دوم، سودِ ریالیِ این جفت هرچه مظنه بشود عوض نمیشود. همین تعریفِ ریاضیِ پوششِ کامل است — و در آزمونهای پنل با نرخِ ۰٫۶ برابر، ۱ برابر و ۱٫۸ برابر سنجیده میشود و هر سه یک عدد میدهند. اگر همان خرید را پوشش ندهی، اختلافِ همان دو نرخ صدها میلیون ریال است.
#تفاوتِ «معامله» و «تسویه» — مهمترین قانونِ این صفحه
| سندِ معامله | سندِ تسویه | |
|---|---|---|
| نوع سند | خرید / فروش | دریافت / پرداخت |
| فی دارد؟ | بله | خیر |
| در کارکرد سود میسازد؟ | بله | خیر |
طلایی که با «دریافت» یا «پرداخت» جابهجا میشود فی ندارد، چون قیمتش قبلاً در سندِ معاملهٔ اصلی بسته شده. یک حوالهٔ طلا، یک تسویهٔ بدهی با طلا، یک عیارِ تهحساب — هیچکدام معامله نیستند.
پیش از این نسخه، پنل اینها را هم با نرخِ روز میسنجید. اندازهگیریِ واقعی روی خودِ کد نشان داد یک حوالهٔ طلای ۹۵ گرمی روی سندِ «دریافت» بهتنهایی ۱٬۲۶۲٬۶۴۵٬۵۷۵ ریال سودِ خیالی میساخت و یک تسویهٔ ۴۰ گرمی روی «پرداخت» ۵۳۱٬۶۴۰٬۲۴۲ ریال زیانِ خیالی. هر دو حالا صفراند.
حواست باشد: سودِ عیارِ تهحساب دستنخورده مانده — آن سودِ واقعی است و از مسیر جداگانهای میآید. فقط مارکتومارکتِ دروغ حذف شد.
#نگهبانِ ثبتِ اشتباه
اگر روی سندِ دریافت یا پرداخت، ردیفِ طلایی با فی ببیند، بالای صفحه اخطارِ قرمز میآید و میگوید این ردیف باید سندِ خرید یا فروش میبود، با همان وزن و همان فی. چیزی خودکار عوض نمیشود؛ دکمهٔ کنارش سندِ اصلی را باز میکند تا خودت درستش کنی.
امانتِ تعمیر (بخش ۳۲) بیفی است، پس هیچوقت اخطارِ نابهجا نمیگیرد.
#اشتباهِ رایج
پوشش را با سندِ «پرداخت» به بنکدار ثبت میکنی، چون «پول دادم».
پوشش یک فروش/خرید است، نه تسویه. با ثبتِ اشتباه، آن معامله اصلاً واردِ کارکرد نمیشود و اسپردت هیچجا دیده نمیشود. در سنجشِ عملی، همین یک اشتباه گزارشِ یک روز را حدودِ یک میلیارد ریال جابهجا کرد.
#۳۴. تراز خرید و فروش و نوار پایین صفحه
بخشِ ۳۳ گفت چرا باید مظنه را بست. این بخش میگوید چطور در طولِ روز حواست به آن باشد بدون اینکه هر بار گزارش باز کنی.
در یک روزِ شلوغ دهها قلم با وزنهای مختلف میخری و میفروشی. وزنِ تکتکِ فاکتورها مهم نیست؛ آنچه اهمیت دارد خالص است. اگر تهِ روز رویهم ۱۲۳٫۴۹ گرم بیشتر فروخته باشی تا خریده، تا وقتی همان وزن را از بازار نخری هر گرانیای از جیبِ خودت میرود. وقتی این خالص صفر شود میگویند «تراز» هستی.
#نمای زندهٔ تراز معاملهگر — v93
در صفحهٔ پوشش ریسک، کارت «الان روی خرید هستید یا فروش؟» تراز را بدون ساخت گزارش جدا و مستقیماً از اسناد ثبتشده نشان میدهد. ابتدا بازهٔ امروز یا از ابتدا را انتخاب کنید، سپس یکی از چهار مبنا را بزنید:
- فقط طلا: خالص خرید و فروش طلا را به گرم ۷۵۰ نشان میدهد.
- طلا + معادل سکه: خالص طلا را با معادل طلای ۷۵۰ همهٔ سکهها جمع میکند. معادل هر سکه از
تعداد × وزن واحد × عیار ÷ ۷۵۰بهدست میآید. - یک نوع سکه: نوعی مانند امامی یا ربع را انتخاب میکنید و خالص تعداد همان نوع را میبینید.
- همه سکهها با مبنای واحد: همهٔ انواع سکه را با وزن و عیار کاتالوگ به معادل امامی تبدیل میکند؛ اگر امامی در کاتالوگ نباشد، نخستین نوع ثبتشده مبنا میشود. نام مبنا کنار عدد نوشته میشود.
خ یعنی بیشتر خریدهاید و هنوز روی خرید هستید؛ ف یعنی بیشتر فروختهاید و روی فروش هستید؛ صفر یعنی تراز. با کلیک روی کارت نتیجه، ریز اسناد مؤثر باز میشود. حالت طلا اسناد طلایی، حالت سکه اسناد سکه و حالت ترکیبی هر دو را نشان میدهد. اعداد این کارت گزارشاند و هیچ سند یا موجودی را تغییر نمیدهند.
#نوارِ پایینِ صفحه
یک نوارِ باریک همیشه پایینِ پنجره میماند — در همهٔ صفحهها، و با هر سندی که ذخیره میکنی خودش تازه میشود:
امروز [ فروش ـ طلا ۱۲۳٫۴۹۰ گ۷۵۰ ] کلیک: گزارشِ تراز · راستکلیک: تنظیم
- قرمز = روی فروش ماندهای (بیشتر فروختهای تا خریده). گرانشدنِ طلا به ضررت است.
- سبز = روی خرید ماندهای. ارزانشدنِ طلا به ضررت است.
- خاکستریِ صفر = تراز. نوسانِ بازار دیگر کاری به تو ندارد.
کلیک روی نوار، صفحهٔ پوشش ریسک و گزارشِ کاملِ تراز را باز میکند. راستکلیک، همانجا پنجرهٔ «تنظیم تراز» را میآورد تا بدون رفتن به تنظیمات، بازه یا نمایش را عوض کنی.
#گزارشِ «ترازِ خرید و فروش»
در صفحهٔ پوشش ریسک، زیرِ سه کارتِ بالا. هر سندِ طلایی یک سطر است، از قدیم به جدید:
| کد سند | سند | طرف حساب | خرید وزن۷۵۰ | فروش وزن۷۵۰ | ترازِ وزن |
|---|---|---|---|---|---|
| ۳۰۱ | فروش | سحر دولتشاهی | — | ۱۷٫۶۴۰ | ف ۱۷٫۶۴۰ |
| ۳۰۲ | خرید | سحر دولتشاهی | ۵٫۱۱۰ | — | ف ۱۲٫۵۳۰ |
| ۳۰۳ | فروش | سحر دولتشاهی | — | ۱۳٫۵۹۰ | ف ۲۶٫۱۲۰ |
| ۳۰۴ | فروش | سحر دولتشاهی | — | ۷٫۶۴۰ | ف ۳۳٫۷۶۰ |
| ۳۰۵ | خرید | امیر عابدزاده | ۴۲٫۳۷۰ | — | خ ۸٫۶۱۰ |
| ۳۰۶ | فروش | سحر دولتشاهی | — | ۱۲۵٫۳۵۰ | ف ۱۱۶٫۷۴۰ |
| ۳۰۷ | فروش | سحر دولتشاهی | — | ۶٫۷۵۰ | ف ۱۲۳٫۴۹۰ |
| جمع ـ طلا | ۴۷٫۴۸۰ | ۱۷۰٫۹۷۰ | ف ۱۲۳٫۴۹۰ |
(چهار ستونِ دیگر — خرید مبلغ، فروش مبلغ و ترازِ مبلغ — در جدولِ واقعی سمتِ چپ همین ستونها هستند.)
ستونِ ترازِ وزن ماندهٔ همان لحظه است، نه وزنِ آن سند. همین ستون قصه را تعریف میکند:
- سطرِ ۱: فروختی، ۱۷٫۶۴۰ روی فروش رفتی.
- سطرِ ۲: ۵٫۱۱۰ متفرقه خریدی، ماندهٔ باز به ۱۲٫۵۳۰ کم شد.
- سطرهای ۳ و ۴: باز هم فروش، تا ۳۳٫۷۶۰ روی فروش.
- سطرِ ۵: با بازار «پولی کردی» — ۴۲٫۳۷۰ گرم خریدی. از روی فروش رد شدی و ۸٫۶۱۰ روی خرید افتادی.
- سطرهای ۶ و ۷: دو فروشِ دیگر، تا ۱۲۳٫۴۹۰ روی فروش.
«ف» یعنی روی فروش ماندهای، «خ» یعنی روی خرید. جایی که عدد به صفر میرسد، همانجاست که با بازار تراز شدهای. کلیک روی هر سطر، فاکتورِ همان سند را باز میکند.
سطرِ جمع دو خط دارد: جمع ـ طلا (وزن) و جمع ـ ریال (مبلغ).
#دو ستونِ مبلغ چه میگویند
ستونِ مبلغ همان ارزشِ بستهشدهٔ همان طلاست: وزن۷۵۰ × فی + اجرت. پس:
- روی سندِ تسویه (دریافت/پرداخت) مبلغ صفر میماند و این درست است — طلایی که قیمتش با کسی بسته نشده مبلغِ تراز ندارد، فقط وزن دارد. (همان قانونِ بخش ۳۳.)
- اگر وزن تراز شده باشد ولی ترازِ مبلغ صفر نباشد، آن اختلاف همان چیزی است که از اسپردِ مظنه بهدست آوردهای: ۱۰ گرم به ۳۰ میلیون فروختی و همان ۱۰ گرم را به ۲۸ میلیون خریدی → وزن صفر، مبلغ ۲۰ میلیون به نفعِ تو.
#تنظیمات (تب تنظیمات ← «تراز در نوار پایین»)
| تنظیم | گزینهها | پیشفرض |
|---|---|---|
| بازهٔ تراز | امروز / از ابتدا | امروز |
| ترازِ طلا | فقط خالص / نمایش نده | فقط خالص |
| ترازِ مبلغ | نمایش نده / نمایش بده | نمایش نده |
| ترازِ ارز و سکه | نمایش نده / نمایش بده | نمایش نده |
«از ابتدا» را برای کارِ روزانه انتخاب نکن. همهٔ اسنادِ تاریخِ مغازه را میخواند، کند میشود، و عددی میدهد که تصمیمِ امروزت را عوض نمیکند. برای کنترلِ روزانه «امروز» همان چیزی است که لازم داری؛ «از ابتدا» فقط برای کنترلِ کلیِ دورهای بماند.
اگر هر سه نمایش را «نمایش نده» بگذاری، نوار بهکلی از صفحه برداشته میشود و فضایش پس داده میشود.
#ترازِ ارز و سکه
طلا یک واحد دارد، پس یک ستون برایش بس است. ولی سکه به تفکیکِ نوع تراز میشود و ارز به تفکیکِ واحد — «تمام» و «ربع» را نمیشود با هم جمع زد، دلار و درهم را هم نه. برای همین اینها ستونِ تازه در دفترِ تراز نمیگیرند و جدولِ جداگانهای پایینِ همان صفحهٔ پوشش ریسک میسازند:
| دسته | قلم | خرید | فروش | تراز |
|---|---|---|---|---|
| سکه | تمام بهار آزادی | ۱۲ | ۵ | خ ۷ |
| سکه | ربع بهار آزادی | — | ۳ | ف ۳ |
| ارز | USD | ۲٬۰۰۰ | ۳٬۵۰۰ | ف ۱٬۵۰۰ |
- سکه به تعداد شمرده میشود، نه به ریالش. ردیفِ سکهٔ سند، تعدادش خوانده میشود.
- ارز به واحدِ خودش. منبعش همان ردیفِ کالای غیرطلایی است که فیِ آن به ارز بسته شده (بخش ۳۰).
- ریال اینجا اصلاً دخالت ندارد. آن را «ترازِ مبلغ» جدا نشان میدهد.
- «خ» و «ف» همان معنیِ همیشگی را دارند: سمتی که رویش ماندهای.
روی نوارِ پایین هم حداکثر سه قلمِ نامتراز کنارِ ترازِ طلا مینشیند (نوار جای بیشتری ندارد)؛ بقیه در همین جدول دیده میشوند. قلمی که ترازش صفر است اصلاً نشان داده نمیشود — نه در نوار، نه بهعنوان سطرِ بیفایده.
اگر در بازهٔ انتخابی هیچ سکه و ارزی جابهجا نشده باشد، بهجای جدولِ خالی یک پیامِ ساده میآید.
#نکتهٔ جهت — جایی که آدم قاطی میکند
| یعنی چه | |
|---|---|
| نوار و ستونِ تراز میگوید فروش | سمتی که رویش هستی |
| دکمهٔ «بستنِ مظنه» میگوید خرید | کاری که برای بستنش باید بکنی |
این دو همیشه عکسِ هماند و هر دو درستاند.
#رابطه با «وضعیتِ باز» بالای همان صفحه
عددِ وضعیتِ باز ماندهٔ طلاییِ افتتاحیهٔ اشخاص را هم حساب میکند؛ دفترِ تراز فقط گردشِ اسناد را میشمارد. اگر افتتاحیهای در کار نباشد، ترازِ «از ابتدا» و وضعیتِ باز دقیقاً یک عددند — و این در آزمونهای پنل تضمین شده است.
#قرارداد حساب بینالمللی و اجرت چندارزی — v94
اگر با سازنده یا همکار خارجی کار میکنید، در فرم اشخاص کارت «قرارداد حساب بینالمللی» را تکمیل کنید:
- عیار نمایش حساب، مانند ۹۹۵ یا ۱۰۰۰، فقط مانده و فاکتور همان شخص را به عیار توافقی نمایش میدهد و موجودی فیزیکی را تغییر نمیدهد. وزن واقعی انبار و معادل ۷۵۰ اسناد همان دادهٔ اصلی میمانند.
- ارز پیشفرض اجرت دریافتی هنگام افزودن ردیف طلای سند به فرم اجرت پیشنهاد میشود. تومان، دلار و ارزهای تعریفشده در کاتالوگ مانند درهم قابل انتخاباند.
- دلار از نرخ آنلاین پنل استفاده میکند. برای ارزی که نرخ آنلاین ندارد، نرخ هر واحد به تومان را در قرارداد شخص وارد کنید؛ در فرم اجرت نیز میتوانید نرخ همان معامله را بازبینی کنید.
در سند، نوار «قرارداد این حساب» عیار نمایشی، ارز اجرت و نرخ قابل استفاده را نشان میدهد. این پیشنهاد، اجرت تعریفشدهٔ خود جنس را حذف نمیکند؛ تا زمانی که اجرت را ثبت نکردهاید، کاتالوگ و میانگین فی دریافتی همچنان میتوانند مقدار اولیه را پیشنهاد دهند.
#ثبت نرخ و محاسبهٔ سود
برای اجرت گرمی یا عددی، نرخ تبدیل هنگام ثبت روی خود ردیف بهصورت snapshot ذخیره میشود. بنابراین بالا یا پایین رفتن نرخ دلار و درهم در روزهای بعد، مبلغ و سود معاملهٔ قبلی را بازنویسی نمیکند. ردیفهای قدیمی دلاری که snapshot ندارند برای سازگاری از نرخ زنده استفاده میکنند.
اجرت ارزی ابتدا با نرخ snapshot به تومان تبدیل میشود و سپس از همان مسیر محاسبهٔ مبلغ سند و گزارش سود و زیان میگذرد. برای ارز دستی، ثبت اجرت بدون نرخ تبدیل مجاز نیست. اجرت درصدی وابسته به ارزش طلاست و ارز مستقل ندارد.
#گزارش موجودی بر اساس ارز اجرت
در کالا و انبار ← موجودی اجناس، پایین جدول موجودی کارتهای «موجودی و اجرت دریافتی، به تفکیک ارز» دیده میشوند. هر کارت این موارد را جداگانه نشان میدهد:
- وزن و تعداد موجودی؛
- میانگین وزنی فی دریافتی؛
- میانگین درصد اجرت؛
- جمع اجرت فی بر پایهٔ موجودی فعلی.
ارز هر قلم از «تعریف جنس ← ارز دریافتی» خوانده میشود. دلار، درهم و سایر ارزها با هم جمع نمیشوند؛ اگر جنس در گروه اشتباه دیده میشود، ارز دریافتی همان جنس را اصلاح کنید.
#تبدیل مستقیم ارز به ارز (اکسچنج) — v95
برای خرید یک ارز در برابر ارز دیگر، در صفحهٔ ثبت سند دکمهٔ تبدیل ارز را بزنید. این مسیر برای صرافی و معاملههایی است که تسویهشان ریالی نیست؛ مانند دریافت ۳٬۰۰۰ یورو و پرداخت دلار به همان طرف حساب.
- طرف حساب را انتخاب کنید.
- در کارت سبز، ارز و مقدار دریافتی را بنویسید.
- در کارت قرمز، ارز پرداختی را انتخاب کنید.
- نرخ قطعی را به شکل «هر یک واحد ارز دریافتی چند واحد ارز پرداختی است» وارد کنید. مقدار پرداختی خودکار محاسبه میشود.
- پیشنمایش را کنترل کنید و پیشنویس اکسچنج را بسازید؛ سپس سند را مانند اسناد دیگر بررسی و ذخیره کنید.
مثلاً اگر ارز دریافتی یورو، مقدار ۳٬۰۰۰، ارز پرداختی دلار و نرخ ۱٫۱۵۸۹۸ باشد، پنل پرداخت ۳٬۴۷۶٫۹۴ دلار را محاسبه میکند. در ماندهٔ طرف حساب، ۳٬۰۰۰ یورو بهعنوان بدهی او و ۳٬۴۷۶٫۹۴ دلار بهعنوان طلب او ثبت میشود. دو ارز با هم یا با ریال جمع نمیشوند.
نرخ، مقدار مبنا و مقدار نهایی بهصورت snapshot روی همان سند ذخیره میشوند. بنابراین تغییر نرخ آنلاین یا نرخهای کاتالوگ، اکسچنج قدیمی را بازنویسی نمیکند. دکمهٔ گرد میان دو کارت، جهت معامله را جابهجا و نرخ را معکوس میکند.
مرز مهم: اکسچنج دو ردیف مستقل دارد: یک ردیف «ورود» برای ارز دریافتی و یک ردیف «خروج» برای ارز پرداختی. حذف یکی از این ردیفها سند را یکطرفه و مانده را نادرست میکند. ارز دو سمت نیز باید متفاوت باشد.
#۳۵. مرجوعی در تکفروشی: وقتی مشتری جنس را پس میآورد
بخشِ ۴ گفت «مرجوع» یعنی چه. این بخش میگوید چطور بیاشتباه ثبتش کنی — چون اینجا جایی است که یک ثبتِ بهظاهر درست، پول را بیسروصدا میخورد.
#چرا «دریافتِ عادی» جوابِ درستی نیست
مبلغِ یک قلمِ تکفروشی سه لایه است:
| لایه | مثالِ نیمستِ ۱۰٫۳۷ گرمی |
|---|---|
| طلای خام (وزن۷۵۰ × قیمت طلا) | ۲۶۴٫۴۳۵٫۰۰۰ |
| اجرتِ ساخت (۱۱٪) | ۲۹٫۰۸۷٫۸۵۰ |
| سودِ فروشنده (۷٪) + مالیاتِ آن (۹٪) | ۲۵٫۰۱۳٫۷۰۱ |
| جمع — همان مبلغی که از مشتری گرفتی | ۳۱۸٫۵۳۶٫۵۵۱ |
اگر بازگشتِ همین جنس را با یک ردیفِ «دریافت» ثبت کنی، فقط دو لایهٔ اول برمیگردد. لایهٔ سوم — ۲۵٫۰۱۳٫۷۰۱ ریال — در فاکتور جا میماند و مشتری به همان اندازه بدهکار میمانَد. آنوقت باید یک تخفیف یا سندِ اصلاحیِ دستی بزنی تا مانده صفر شود، و آخرش هم به همان مبلغی که بابتِ فروش گرفته بودی نمیرسی.
قاعده: جنسِ برگشتی «معاملهٔ تازه» نیست، فسخِ همان معاملهٔ قدیم است. پس با قیمت و اجرت و سودِ همان فاکتور برمیگردد، نه با نرخِ امروز.
#راهِ درست: دکمهٔ ↩ روی خودِ ردیف
فاکتورِ فروش را باز کن، روی ردیفِ همان قلم دکمهٔ ↩ را بزن (یا ردیف را انتخاب کن و Ctrl+R). یک پنجره باز میشود که پیش از هر کاری مشخصاتِ همان ردیف را نشانت میدهد: وزن، عیار، قیمتِ همان فاکتور و مبلغِ ردیف. یعنی میبینی دقیقاً چه چیزی برمیگردد.
دو انتخاب داری:
| گزینه | کِی |
|---|---|
| ↩ همین سند | مشتری همان روز و پیش از تسویه پس آورد. ردیفِ مرجوعی بیفاصله زیرِ همان ردیفِ فروش مینشیند. |
| سند جدید | فاکتور بسته و تسویه شده و مشتری چند روز بعد آمده. یک سندِ تازه به نامِ همان شخص با یادداشتِ «مرجوعی سند ۲۴۵» ساخته میشود. |
یک تیک هم دارد: «سودش را برنگردان». برای وقتی که توافق کردهاید اجرت و طلا برگردد ولی سودِ فروشنده پیشِ تو بماند. با این تیک همان ۲۵٫۰۱۳٫۷۰۱ ریال برنمیگردد و بقیه برمیگردد.
هیچکدام از دو گزینه سند را ذخیره نمیکند. ردیف ساخته و پیشرویت گذاشته میشود؛ دستت باز است وزن را نصف کنی (مرجوعیِ جزئی)، اجرت را دست بزنی، یا کلاً پشیمان شوی. ذخیره کارِ خودت است.
#قصهٔ کاملِ یک مرجوعی
فاکتورِ پنجشنبه ۱۴۰۲/۰۲/۲۸ — قیمتِ طلا ۲۵٫۵۰۰٫۰۰۰:
| # | تاریخ | تشخیص | شرح | وزن | ٪اجرت | مبلغ |
|---|---|---|---|---|---|---|
| ۱ | ۰۲/۰۲/۲۸ | فروش | النگو کد ۱۲۵ | ۱۵٫۰۳ | ۱۶ | ۴۸۴٫۰۲۸٫۴۳۵ بد |
| ۲ | ۰۲/۰۲/۲۸ | فروش | نیمست قلب | ۱۰٫۳۷ | ۱۱ | ۳۱۸٫۵۳۶٫۵۵۱ بد |
| ۳ | ۰۲/۰۲/۲۸ | دریافت | حوالهٔ علی فردوسی | — | — | ۸۰۲٫۵۶۴٫۹۸۵ بس |
| ۴ | ۰۲/۰۲/۳۰ | مرجوع | نیمست قلب | ۱۰٫۳۷ | ۱۱ | ۳۱۸٫۵۳۶٫۵۵۱ بس |
| ماندهٔ سند | ۳۱۸٫۵۳۶٫۵۵۰ بس |
سطرِ ۳ کلِ فاکتور را تسویه کرده بود و مانده صفر شده بود. با برگشتِ نیمست در سطرِ ۴، مغازه ۳۱۸٫۵۳۶٫۵۵۰ ریال به مشتری بدهکار میشود — یعنی دقیقاً همان پولی که بابتِ نیمست گرفته بود. آنچه از فاکتور باقی میماند هم دقیقاً ۴۸۴٫۰۲۸٫۴۳۵ است: مبلغِ النگو، بیکموکاست.
#ستونِ «تاریخ» که ناگهان ظاهر میشود
در جدولِ بالا سطرِ ۴ تاریخِ ۳۰ دارد، در حالی که سربرگِ فاکتور ۲۸ است. هر ردیف میتواند تاریخِ خودش را داشته باشد و همینجاست که به کار میآید: جنس روزِ ۲۸ رفته و روزِ ۳۰ برگشته؛ اگر برگشت را به تاریخِ ۲۸ بنویسی، کاردکسِ آن قلم دو روز دروغ میگوید.
ستونِ «تاریخ» فقط وقتی نشان داده میشود که واقعاً ردیفی با تاریخِ مستقل داشته باشی. در فاکتورِ معمولی جدول شلوغ نمیشود. خالی گذاشتنِ خانه یعنی «همان تاریخِ سربرگ»، و زدنِ کلید * تاریخِ امروز را میگذارد.
#نشانههای روی صفحه
- ردیفِ مرجوعی زمینهٔ آبیِ کمرنگ و یک نوارِ آبی در لبه دارد؛ در یک فاکتورِ دهردیفی از دور پیدایش میکنی.
- کنارش یک برچسبِ «↩ ردیف ۲ سند ۲۴۵» مینشیند. اگر مرجوعی در سندِ دیگری باشد، این برچسب کلیکشدنی است و فاکتورِ مبدأ را باز میکند.
- خانهٔ «شرح» در ردیفِ مرجوعی، فهرستِ اجناسی که قبلاً با همین نوعِ سند به همین شخص رفته را پیشنهاد میدهد — نه کلِ انبار. پس اسمِ قلم را همانطور که در فاکتورِ اصلی نوشته بودی مینویسی و کاردکس دو قلمِ همنامِ جدا نمیسازد.
- روی فاکتورِ چاپی هم زیرِ شرحِ ردیف نوشته میشود «برگشتِ ردیف ۲ سند ۲۴۵» و اگر تاریخِ ردیف با سربرگ فرق داشت، «تاریخ ردیف: ۱۴۰۲/۰۲/۳۰». مشتری و حسابرس میفهمند این سطرِ منفی برگشتِ کدام قلم و کدام روز است.
#چه چیزی مرجوع نمیشود
دکمهٔ ↩ روی این ردیفها نمیآید: ردیفی که خودش مرجوعی است (وگرنه با دو کلیک فروش را دوباره برمیگرداندی)، ردیفِ تخفیف، ردیفِ خالی، و هر ردیفی در سندِ «سایر» (که تشخیصِ مرجوع ندارد). ردیفِ نقد و چک مرجوعشدنی است — ولی خودِ برگهٔ چک کپی نمیشود تا دفترِ چک دوقلو نسازد.
#جای دیگری که اثرش را میبینی
| کجا | چه میشود |
|---|---|
| کاردکسِ قلم (بخش ۲۷) | مرجوعی یک حرکتِ ورود به تاریخِ خودش است. رفت و برگشتِ کامل، موجودی را به صفر میرساند. |
| ترازِ خرید و فروش (بخش ۳۴) | مرجوعیِ یک فروش خودبهخود در ستونِ خرید مینشیند، چون جهتِ مؤثرش برعکس شده. |
| ریز ورود و خروج (بخش ۲۵) | همان قلم از سمتِ «خروج» به سمتِ «ورود» جابهجا میشود. |
| مالیات (بخش ۷) | سود و مالیاتِ سند روی خالص حساب میشود: طلا و اجرتِ مرجوعی از پایهٔ محاسبه کم میشود. |
| سودِ عیارِ تهحساب (بخش ۱۵) | اگر جنس با عیارِ شخصی فروخته شده بود، مرجوعی همان سودِ عیار را هم پس میدهد. |
#۳۶. سکهٔ پارسیان: اجرت عددی و معافیت ارزش افزوده
سکهٔ پارسیان دو جای فرمولِ همیشگی را میشکند و اگر هر دو را رعایت نکنی، فاکتور بیسروصدا غلط درمیآید:
- اجرتش به دانه بسته است، نه به گرم. پارسیانِ ۵۰۰ سوتی و پارسیانِ ۱ گرم و ۲۰ ممکن است اجرتِ یکسان داشته باشند.
- ارزش افزوده ندارد. ولی سودِ تکفروشی را دارد — این دو را با هم قاطی نکن.
#اجرت عددی
روی ردیفِ طلا، دکمهٔ اجرت (⚖) را بزن و «عددی (هر دانه)» را انتخاب کن. آنوقت:
اجرت = تعداد × فی
نه وزن، نه درصد. اگر ۹ دانه پارسیان با اجرتِ ۱۰۰ هزار تومانی گرفتهای، اجرتِ کل ۹۰۰ هزار تومان است — چه مجموع وزنشان ۹٫۴ گرم باشد چه ۶ گرم.
چرا اینقدر مهم است؟ اگر همان ۹ دانه را «فی هر گرم» بزنی، برنامه ۹٫۴ × ۱۰۰ هزار = ۹۴۰ هزار تومان حساب میکند. یعنی پارسیانِ سنگین گرانتر و پارسیانِ سبک ارزانتر میشود — در حالی که بنکدار به شما دانهای فروخته است.
تعداد اجباری میشود. روی ردیفی که اجرتش عددی است، سلولِ تعداد طلایی میشود و «لازم» مینویسد. اگر خالی رد شوی، هنگام ثبت پیام میگیری:
تعداد نباید خالی باشد — ردیف ۳
این تنها جایی است که تعداد اجباری است. دلیلش ساده است: بدون تعداد، اجرت صفر میشود و صفر بیصدا ثبت میشود — نه خطایی، نه هشداری، فقط چند میلیون تومان کمتر.
#وزن یکعدد
اگر پارسیانِ هموزن میگیری (مثلاً «۲۰ تا ۵۰۰ سوت»)، در تعریفِ جنس فیلد وزن یکعدد را پر کن (۰٫۵). از آن به بعد کافی است تعداد را بزنی؛ وزن خودش پر میشود:
| تعداد | وزن یکعدد | وزن ردیف |
|---|---|---|
| ۲۰ | ۰٫۵ | ۱۰٫۰۰۰ گرم |
| ۱۰ | ۰٫۸ | ۸٫۰۰۰ گرم |
اگر پارسیانِ گلهای (وزنهای قاطی) میگیری، وزن یکعدد را خالی بگذار و وزنِ مجموع را دستی بزن — برنامه دست نمیزند.
برای پارسیانِ هموزن بهتر است جنسها را جدا تعریف کنی: «پارسیان ۵۰۰ سوتی» و «پارسیان ۸۰۰ سوتی». آنوقت در گزارش موجودی اجناس هرکدام ردیف و شمارِ خودش را دارد.
#معافیت ارزش افزوده
در تعریف جنس، تیکِ «ارزش افزوده دارد» را بردار. از آن لحظه، ردیفهای تازهٔ این جنس معاف میشوند و کنار مبلغشان برچسبِ سبزِ «معاف از م.ا.ا» میآید.
معافیت فقط مالیات را برمیدارد. سه لایهٔ مبلغ اینطور میشود:
| لایه | جنس عادی | پارسیان |
|---|---|---|
| مبلغ طلای خام | ✔ | ✔ |
| اجرت | ✔ | ✔ |
| سود تکفروشی | ✔ | ✔ (سرِ جایش هست) |
| مالیات ارزش افزوده | ✔ | ✖ |
مثال واقعی — پارسیان، وزن ۷۵۰ برابر ۲٫۰۰ گرم، قیمت طلا ۱۵٬۰۸۹٬۰۰۰، اجرت ۲ دانه × ۱٬۲۰۰٬۰۰۰، سود ۷٪، مالیات ۹٪:
| با ارزش افزوده | بدون ارزش افزوده | |
|---|---|---|
| مبلغ طلای خام | ۳۰٬۱۷۸٬۰۰۰ | ۳۰٬۱۷۸٬۰۰۰ |
| اجرت (۲ × ۱٬۲۰۰٬۰۰۰) | ۲٬۴۰۰٬۰۰۰ | ۲٬۴۰۰٬۰۰۰ |
| سود تکفروشی ۷٪ | ۲٬۲۸۰٬۴۶۰ | ۲٬۲۸۰٬۴۶۰ |
| مالیات ۹٪ | ۴۲۱٬۲۴۱ | — |
| مبلغ ردیف | ۳۵٬۲۷۹٬۷۰۱ | ۳۴٬۸۵۸٬۴۶۰ |
اختلاف دقیقاً ۴۲۱٬۲۴۱ ﷼ است — یعنی ۹٪ روی (اجرت + سود)، نه یک ریال بیشتر.
#معافیت ردیفی است، نه سندی
در یک فاکتور میتوانی همزمان طلای ساختهٔ مشمول و پارسیانِ معاف داشته باشی. برنامه مالیات را فقط از ردیفهای مشمول میگیرد. در کارت مالیاتِ پایین سند یک سطر اضافه میشود:
کسرِ معافیت (اجرت + سودِ ردیفهای معاف) −۴٬۶۸۰٬۴۶۰
این سطر برای این است که وقتی مالیات کمتر از انتظارت شد، همانجا بفهمی چرا — نه اینکه دنبال اشکالی بگردی که وجود ندارد.
#⚠ ردیفهایی که قبلاً زدهای عوض نمیشوند
معافیت روی خودِ ردیف ذخیره میشود، نه خواندهشده از کاتالوگ. پس اگر ردیفی را زدی و بعد ارزش افزودهٔ آن جنس را غیرفعال کردی:
آن ردیف را پاک کن و دوباره بزن.
این عمدی است. اگر معافیت از کاتالوگ خوانده میشد، غیرفعالکردنِ ارزش افزودهٔ پارسیان امروز، مالیاتِ همهٔ فاکتورهای پارسال را هم پاک میکرد. سندِ ثبتشده باید همان مالیاتی را نشان بدهد که روز ثبت داشت.
#شمارش در موجودی اجناس
تعدادِ ردیفهای طلا در گزارشِ موجودی اجناس جمع میشود. اگر ۷ دانه پارسیان داشتی و ۳ دانه خریدی، موجودی میشود ۱۰ دانه — با وزنش، کنار هم. ردیفِ معاف هم شمرده میشود؛ معافیت یک موضوع مالیاتی است، نه انبارداری.
#نمای جدید گزارش موجودی اجناس (v112)
در کالا و انبار ← موجودی اجناس، ابتدای صفحه یک خلاصهٔ چهاربخشی دیده میشود تا بدون گشتن میان ستونها وضعیت ویترین را بررسی کنید:
| باکس | چه چیزی نشان میدهد |
|---|---|
| قلم موجودی | تعداد عنوانهای ثبتشده در جدول |
| وزن ثبتشده | جمع وزن فعلی ردیفها به گرم |
| ارزش ثبتشده | جمع مبلغهای ریالی واردشده برای ردیفها |
| دارای فی یا درصد | چند قلم برای اجرت، فی یا درصد معتبر دارند |
زیر این باکسها، جستوجوی زنده قرار دارد. با نوشتن نام کالا، سازنده، عیار یا بارکد فقط ردیفهای منطبق باقی میمانند و شمارنده همان لحظه تعداد نتیجهها را اعلام میکند. جستوجو چیزی را از انبار حذف یا در اطلاعات ذخیره نمیکند؛ فقط نمایش جدول را محدود میکند.
هر مقدار داخل باکس ورودی خودش نمایش داده میشود و در انتهای هر ردیف مسیرهای عملیاتیِ همان قلم در دسترساند: چاپ و رهگیری لیبل، ویرایش جنس و سازنده، گردش موجودی، تفکیک، اصلاح موجودی و حذفِ مجاز. در موبایل، خلاصه و دکمهها به کارتهای تکستونه یا دوستونه تبدیل میشوند و جدول اصلی برای حفظ همهٔ ستونهای حسابداری اسکرول افقی دارد. حالت تاریک، فوکوس صفحهکلید و کاهش حرکت نیز پشتیبانی میشوند.
کنترل اجرت: کم بودن عدد «دارای فی یا درصد» یعنی بعضی اقلام هنوز مبنای اجرت ندارند. پیش از فروش، ستونهای فی یا ٪ را کامل کنید تا اجرت پیشنهادی و گزارش سود قابل اتکا باشد.
#ستون «فی دریافتی» و درپیجِ ردیابی (v113)
در همان جدولِ موجودی اجناس، کنارِ ستونِ ٪ یک ستونِ تازهٔ «فی دریافتی» اضافه شده است. این ستون میانگینِ وزنیِ چیزی که همان جنس پای تو افتاده را نشان میدهد — یعنی بهطور میانگین هر گرمِ این قلم را با چه فی یا چه درصدی خریدهای. عدد خواندنی است و از همان مبنایی خوانده میشود که گزارشِ کارکرد اجناس رویش بسته شده (gpBasis)، پس پیشنهادِ فی، ستونِ موجودی و گزارشِ سود هیچوقت سه حرفِ متفاوت نمیزنند.
- اگر مبنای درصدی باشد، به شکلِ
٪…و اگر ریالی باشد به شکلِ مبلغ نمایش داده میشود. - اگر جنسی هنوز هیچ ورودیای نداشته باشد، بهجای عدد یک خط تیرهٔ خنثی (—) دیده میشود.
روی چیپِ عددِ هر ردیف که کلیک کنی، یک درپیجِ مدرن باز میشود که نشان میدهد این میانگین از کجا آمده: کارتِ خلاصهٔ بالا (وزنِ مبنا و میانگینِ نهایی) و زیرِ آن جدولِ تراکنشها بهترتیبِ تاریخ — موجودیِ اول دوره و هر سندِ ورودی که واردِ میانگین شده، همراه با میانگینِ متحرک بعد از هر ردیف. برای ردیفهای خروجی هم سودِ طلای همان حرکت با فرمولِ گزارش (جهت × وزن۷۵۰ × (درصدِ ردیف − درصدِ دریافتی) ÷ ۱۰۰) نمایش داده میشود. این درپیج محاسبهٔ موازی ندارد؛ دقیقاً همان اعداد را باز میکند تا رَدِ خرابیِ فی را پیدا کنی.
کجا به کار میآید: وقتی در گزارشِ کارکرد اجناس یک زیانِ غیرمنتظره میبینی، لازم نیست اسناد را دستی بگردی — روی همین چیپ کلیک کن تا ببینی میانگینِ فی دریافتی بعد از کدام سند و با چه ورودیای عوض شده است.
جدول و درپیج در موبایل به چیدمانِ کارتمحور تبدیل میشوند و حالتِ تاریک، فوکوس صفحهکلید و کاهش حرکت را پشتیبانی میکنند.
#فیلترِ «به انتخاب خودم» برای گزارش موجودی (v114)
کنارِ جستوجوی زنده، دکمهٔ «به انتخاب خودم» اضافه شده است تا گزارش موجودی اجناس را دقیقاً به همان چیزی که میخواهی محدود کنی — بدون تایپکردنِ نامها. با کلیک روی آن یک پنلِ مدرن باز میشود با سه دستهٔ قابلتیک:
| دسته | چه چیزی را انتخاب میکنی |
|---|---|
| جنس | یک یا چند عنوانِ مشخص (مثلاً فقط «انگشتر پهلوی» و «سرویس رز») |
| گروه جنس | یک یا چند گروه (مثلاً فقط گروه «النگو»، یا «النگو + پابند + دستبند») |
| سازنده | فقط اجناسِ یک یا چند سازنده (مثلاً هرچه از «سنای زرین» است) |
قاعدهٔ ترکیب ساده است: داخلِ یک دسته «یا» و بینِ دستهها «و». یعنی اگر گروهِ «انگشتر» و سازندهٔ «سنای زرین» را با هم تیک بزنی، فقط انگشترهایی که سازندهشان سنای زرین است لیست میشوند. هر دسته یک جستوجوی کوچکِ داخلی و شمارندهٔ تعداد قلمِ هر مقدار دارد.
- گروه و سازندهٔ هر جنس از اطلاعات پایهٔ اجناس خوانده میشود؛ همانجا که هنگام تعریفِ جنس گروه و سازندهاش را مشخص میکنی.
- انتخابهای فعال به شکلِ چیپهای حذفشدنی زیرِ نوار نشان داده میشوند؛ هر چیپ یک ضربدر دارد و یک دکمهٔ «پاک کردن همه» هم هست.
- این فیلتر با جستوجوی متنی همزمان کار میکند و شمارندهٔ «نمایش … از … قلم» را همان لحظه بهروز میکند. فیلتر فقط نمایشِ جدول را محدود میکند و چیزی را از انبار حذف نمیکند.
پنل در موبایل به چیدمانِ تکستونه تبدیل میشود و حالتِ تاریک و کاهش حرکت را پشتیبانی میکند.
#بررسی هشدارها در گزارش موجودی (v115)
گاهی عددِ «فی دریافتی» یا موجودیِ یک جنس اختلافِ فاحش دارد و نباید کورکورانه به آن اعتماد کرد. حالا هر ردیفی که چنین مشکلی داشته باشد، در ستونِ «فی دریافتی» بهجای عددِ آرام، یک چیپِ قرمزِ هشدار نشان میدهد؛ با کلیک روی همان علامت، همان کارکردِ اجناس باز میشود تا موردش را ردیفبهردیف بررسی کنی. بالای جدول هم یک بنرِ خلاصه میگوید چند قلم هشدار دارند و دکمهٔ «فقط هشداردارها» فهرست را فقط به همان اقلام محدود میکند.
هشدارها فقط برای خطاهای قطعی روشن میشوند، نه اختلافِ طبیعیِ فیهای متفاوت (که میانگینِ وزنی خودش میپوشاند). چهار حالت هشدار میگیرد:
| هشدار | یعنی چه | چه کنم |
|---|---|---|
| میانگینِ فیِ دریافتی منفی | جمعِ ورودیها فی یا درصدِ منفی داده | سندی که اجرت را منفی زده یا برگشتیِ اشتباه را پیدا و اصلاح کن |
| ورودی با فیِ منفی | دستِکم یک خرید/دریافت فی یا درصدِ منفی دارد | معمولاً «-» اشتباهی خورده؛ همان سند را بازبینی کن |
| خروج بدونِ پایهٔ فی | فروش/خروج هست ولی هیچ ورودیِ پایهسازی نیست | ابتدا خرید یا دریافتِ آن جنس را ثبت کن؛ سود روی هیچ سنجیده میشود |
| موجودیِ منفی | بیش از آنچه داشتهای خارج شده | سندِ خروج یا موجودیِ اول دوره را بررسی کن |
داخلِ درپیجِ کارکرد هم یک بنرِ قرمز همین دلایل را با توضیح نشان میدهد تا بدانی دقیقاً کدام رویداد باعثِ هشدار شده است. بنر و چیپ و درپیج همگی از یک منبع ساخته میشوند؛ پس هرچه چیپ میگوید، دقیقاً همان است که درپیج توضیح میدهد. این بخش هم حالتِ تاریک، چیدمانِ موبایل و کاهش حرکت را پشتیبانی میکند.
#ربط این بخش به بقیهٔ راهنما
| موضوع | کجا |
|---|---|
| فرمول سهلایهٔ مبلغ و کارت مالیات | §۷ |
| مرجوعی و پسدادن سهمِ سود و مالیات | §۳۵ |
| کالای غیرطلایی (که وزنِ ۷۵۰ ندارد) | §۳۰ |
| شمارش و گردش موجودی هر قلم | §۲۷ |
| عکس و تعریف اجناس | §۱۷ |
#۳۷. فروش قسطی: قسط ریالی و قسط طلایی
کجاست: صفحهٔ سند ← دکمهٔ «قسطبندی» بالای صفحه (میانبر Ctrl+G).
مشتری جنس را امروز میبرد و پولش را چند ماه بعد میدهد. سؤالِ اصلی این است که بدهیاش با چه واحدی قفل شود — ریال یا طلا؟ همین یک انتخاب، همهٔ ریسکِ نوسانِ طلا را جابهجا میکند.
#دو حالت، دو ریسکِ متفاوت
| ریالی | طلایی | |
|---|---|---|
| بدهی با چه چیزی قفل میشود | مبلغ ریالی | گرمِ ۷۵۰ |
| اقساط چطور پرداخت میشوند | مبلغ ثابتِ ماهانه | وزنِ ثابتِ ماهانه (به قیمتِ روزِ پرداخت) |
| اگر طلا گران شود | ضررِ مغازه — پولِ کمارزشتر میگیری | مشتری همان گرم را میدهد، ارزشش حفظ شده |
| اگر طلا ارزان شود | مغازه جلو میافتد | مشتری کمتر میپردازد |
| مناسبِ چه کسی | اقساطِ کوتاه، بازارِ آرام | اقساطِ بلند، بازارِ پرنوسان |
در حالتِ طلایی، مظنهٔ همان لحظه روی سند قفل میشود و دیگر تکان نمیخورد. یعنی بدهی از «۸۲ میلیون ریال» تبدیل میشود به «۳٫۹۱ گرمِ ۷۵۰» و از آن به بعد دفتر با گرم حساب میکند، نه با ریال.
#فرمولِ سود — ساده است، نه مرکب
سودِ کل = مبلغ بدهی × درصد × تعدادِ اقساط
مبلغ کل = مبلغ بدهی + سودِ کل
هر قسط = مبلغ کل ÷ تعدادِ اقساط
درصد برای هر دوره است، نه برای کلِ قرارداد. پس «۳٪ در ۴ قسط» یعنی ۱۲٪ روی کلِ بدهی. سود روی ماندهٔ نزولی حساب نمیشود و مرکب هم نیست — همان روشی که در بازار طلا رایج است.
مثالِ واقعی (سندِ ۱۱۴): بدهی ۷۳٬۱۵۹٬۳۸۸ ریال، ۳٪، ۴ قسط → سود ۸٬۷۷۹٬۱۲۷ · مبلغ کل ۸۱٬۹۳۸٬۵۱۵ · هر قسط ۲۰٬۴۸۴٬۶۲۹ ریال.
در حالتِ طلایی، همین مبلغ کل بر قیمتِ هر گرمِ ۷۵۰ تقسیم میشود:
معادلِ طلا = مبلغ کل ÷ قیمتِ هر گرمِ ۷۵۰ (گِرد به سوت)
وزنِ هر قسط = معادلِ طلا ÷ تعدادِ اقساط (باز هم گِرد به سوت)
⚠ گِردکردن دو بار انجام میشود و این عمدی است. مثالِ سندِ ۱۱۵: مبلغ کل ۷۶٬۰۶۰٬۴۲۹ و قیمت ۲۲٬۰۰۰٬۰۰۰ → معادل ۳٫۴۶ گرم → هر قسط ۳٫۴۶ ÷ ۴ = ۰٫۸۷ گرم. اگر یکجا حساب میشد (۷۶٬۰۶۰٬۴۲۹ ÷ ۲۲٬۰۰۰٬۰۰۰ ÷ ۴) جواب ۰٫۸۶ میشد و مشتری هر ماه یک سوت کمتر میداد؛ آخرِ کار جمعِ اقساط با بدهی نمیخواند.
#درصد و سود، دوطرفهاند
گاهی توافق روی درصدِ گِرد است («۳ درصد») و گاهی روی سودِ گِرد («۹ میلیون تمام»). هر کدام را که بنویسی، آن یکی خودش پر میشود:
- درصد را بنویس → سود حساب میشود.
- سودِ کل را بنویس → درصد از رویش برگردانده میشود (مثلاً ۹٬۰۰۰٬۰۰۰ روی همان بدهیِ سندِ ۱۱۴ میشود ۳٫۰۸٪ و هر قسط ۲۰٬۵۳۹٬۸۴۷ ریال).
#پرکردنِ فرم
| فیلد | پیشفرض | نکته |
|---|---|---|
| مبلغ بدهی | ماندهٔ همین سند | قابلِ ویرایش — برای قسطبندیِ بخشی کمترش کن |
| دورهٔ پرداخت | ماهانه | یا هفتگی |
| تعداد اقساط | — | اجباری؛ تا پرش نکنی دکمهٔ ثبت کار نمیکند |
| درصد سود | — | برای هر دوره |
| سودِ کل | از درصد | یا مستقیم بنویس |
| سررسیدِ اولین قسط | تاریخِ سند + ۱ ماه | کلید * تاریخِ امروز را میگذارد |
| قیمت هر گرمِ ۷۵۰ | فیِ طلای همین سند | فقط در حالتِ طلایی |
پایینِ فرم جدولِ کاملِ اقساط زنده ساخته میشود — با شمارهٔ قسط، تاریخِ سررسید، روزِ هفته و مبلغ (یا وزن). قبل از ثبت دقیقاً همان چیزی را میبینی که در سند خواهد نشست.
#قسطبندیِ بخشی: وقتی فقط اصلِ طلا را قسطی میکنی
اجرت، مالیات و سودِ فروشنده معمولاً باید نقدی بمانند و فقط ارزشِ خودِ طلا قسطی شود. برای این کار مبلغ بدهی را دستی کم کن:
مثالِ واقعی (سندِ ۱۴۵): ماندهٔ سند ۵۱۱٬۳۴۰٬۲۱۱ بود، ولی فقط ۴۲۸٬۶۵۰٬۰۰۰ (اصلِ طلا) قسطی شد → سود ۵۱٬۴۳۸٬۰۰۰ · معادل ۱۵٫۹۸ گرم · هر قسط ۴٫۰۰ گرم. باقیماندهٔ ۸۲٬۶۹۰٬۲۱۱ ریالی ماند و در سندِ بعدی جداگانه ریالی قسطبندی شد (سود ۹٬۹۲۲٬۸۲۵ · هر قسط ۲۳٬۱۵۳٬۲۵۹).
#چه ردیفهایی در سند ساخته میشوند
| ردیف | نقش | مبلغِ امروز |
|---|---|---|
| تبدیل بدهی به طلا | بدهیِ ریالی را میبندد | منفیِ مبلغ کل |
| اصلِ بدهیِ قسطی (طلا) | همان مبلغ را به گرمِ ۷۵۰ بدهکار میکند | ندارد (وزن دارد) |
| قسط ۱ از N … | تعهدِ آینده — سررسید و مبلغ/وزن | صفر |
| سود قسط | تنها ردیفی که واقعاً بدهی میسازد | سودِ کل |
چرا ردیفهای قسط مبلغ ندارند؟ چون قسط، بدهیِ امروز نیست؛ یادداشتِ تعهدِ آینده است. اگر مبلغ میداشتند، ماندهٔ سند دو برابرِ واقعیت میشد: یکبار بابتِ خودِ بدهی و یکبار بابتِ جمعِ اقساط.
دو ردیفِ اولی فقط در حالتِ طلایی ساخته میشوند. نتیجهشان این است که ماندهٔ ریالیِ سند دقیقاً صفر میشود و کلِ بدهی به ستونِ طلا میرود.
#ردیفهای قسط در جدول چه شکلیاند
نوارِ آبیِ کمرنگ، برچسبِ «قسط n از N»، تاریخِ سررسیدِ قابلِ ویرایش، نامِ روزِ هفته و مبلغ (یا وزنِ) قسط. اگر سررسیدی گذشته باشد ردیف قرمز میشود و برچسبِ «سررسید گذشته» میگیرد.
سررسیدِ تکِ یک قسط را میشود دستی جابهجا کرد؛ بقیهٔ الگو بههم نمیریزد. برای وقتی که با مشتری سرِ یک قسطِ خاص جداگانه توافق کردهای.
پایینِ سند هم یک کارتِ خلاصه میآید: نوعِ قسطبندی، مظنهٔ قفلشده، بدهیِ پایه، سود، مبلغ کل، مبلغِ هر قسط، سررسیدِ بعدی و تعدادِ اقساطِ عقبافتاده.
#تغییرِ نقشه پس از ثبت
دکمهٔ «قسطبندی» را دوباره بزن. فرم با همان اعدادِ قبلی باز میشود و بالایش هشدار میدهد که نقشهٔ قبلی برداشته و از نو ساخته خواهد شد.
لازم نیست چیزی را دستی پاک کنی. تعویضِ ریالی↔طلایی، تغییرِ تعدادِ اقساط یا هر ویرایشِ دیگری، ردیفهای قبلی — از جمله ردیفِ تبدیلِ طلا و ردیفِ سود — را خودش برمیدارد. پس سود هرگز روی سود نمینشیند و ثبتِ دوباره مانده را دوبار حساب نمیکند.
برای برداشتنِ کاملِ قسطبندی، دکمهٔ «برداشتنِ قسطبندی» داخلِ همان فرم است. ردیفهای عادیِ سند دستنخورده میمانند.
#⚠ ضمانت را داخلِ این سند ننویس
چک یا طلایی که مشتری بهعنوانِ ضمانت میگذارد، پرداختِ قسط نیست و مالِ مغازه هم نشده. اگر داخلِ سندِ فروش بنویسیاش دو چیز خراب میشود:
- سیستم آن را پرداختِ بدهی میشمارد و ماندهٔ مشتری اشتباه میشود.
- اگر طلا باشد، به موجودیِ اجناس اضافه میشود؛ جنسی که فروشی نیست وارد انبار میشود.
راهِ درست: یک شخصِ جدا بساز (مثلاً «سلطانی ـ ضمانت») و ضمانت را با سندِ امانات ثبت کن. موقعِ تسویه، همان سندِ امانات را برگردان. → §۱۰
#ربط این بخش به بقیهٔ راهنما
| موضوع | کجا |
|---|---|
| مانده و بدهکار/بستانکار | §۲ |
| وزن ۷۵۰ و تبدیل عیار | §۶ |
| امانات و ثبت ضمانت | §۱۰ |
| اجرت، سود فروشنده و مالیات (که معمولاً نقدی میمانند) | §۷ |
| چکِ ضمانت و سررسیدهایش | §۲۸ |
| قفلکردنِ مظنه از راهِ دیگر (پوشش ریسک) | §۳۳ |
| ریز ورود و خروج (که ردیفهای قسط را نشان نمیدهد) | §۲۵ |
| دریافتِ خودِ اقساط (پول، طلا، سکه، ارز) | §۳۸ |
#۳۸. دریافت قسط: وقتی مشتری پولِ قسط را میآورد
کجاست: سه راه، هر سه به یک پنجره میرسند — ۱) صفحهٔ نخست ← پنلِ «اقساطِ سررسیدشده» ← دکمهٔ کیفِ پول جلوی نامِ مشتری. ۲) صفحهٔ سند ← دکمهٔ «دریافت قسط» در سربرگِ سندِ فروشِ قسطی. ۳) روی خودِ ردیفِ قسط در جدولِ سند ← دکمهٔ کیفِ پول.
بخشِ قبل بدهی را قسطبندی کرد. این بخش دربارهٔ همان روزی است که مشتری میآید و میگوید «قسطِ این ماهم». کارِ سنگینِ این صفحه یک جملهٔ ساده است که در دفترهای دستی همیشه دردسر بوده:
هرچه کم بدهد یا زیاد بدهد، میرود روی قسطِ ماهِ دیگر.
#قاعدهٔ تتمّه — قلبِ این بخش
هر قسط سهمِ خودش از کل را دارد. وقتی مشتری کم یا زیاد پرداخت کند، همان اختلاف — نه بیشتر و نه کمتر — به قسطِ بلافاصله بعدی منتقل میشود. قسطهای دورتر دستنخورده میمانند تا نوبتشان برسد.
مثالِ ویدئو (قسطِ طلایی — ۱۱٫۹۸ گرمِ ۷۵۰ در ۴ قسط، سهمِ هر قسط ۲٫۹۹۵ گرم):
| قسط | مقرر | مشتری چه داد | تتمّه | ماندهٔ کلِ حساب |
|---|---|---|---|---|
| ۱ | ۳٫۰۰ گ | ۷۹٬۵۰۰٬۰۰۰ کارتخوان ÷ مظنهٔ ۲۶٬۵۰۰٬۰۰۰ = ۳٫۰۰ گ | −۰٫۰۰۵ (کمی زیاد) | ۸٫۹۸ گ |
| ۲ | ۲٫۹۹ گ | ۵۰٬۰۰۰٬۰۰۰ حواله ÷ مظنهٔ ۲۴٬۴۹۳٬۰۰۰ = ۲٫۰۴ گ | ۰٫۹۵ کم آورد | ۶٫۹۴ گ |
| ۳ | ۳٫۹۵ گ | گوشوارهٔ متفرقهٔ ۴٫۲۶ گرمِ عیارِ ۷۴۰ = ۴٫۲۰ گ | −۰٫۲۶ (زیاد داد) | ۲٫۷۴ گ |
| ۴ | ۲٫۷۴ گ | — | — | — |
ستونِ «مقرر» را برنامه هر بار از نو حساب میکند؛ عددِ اولیهٔ نقشه (۲٫۹۹۵) فقط نقطهٔ شروع است. قسطِ سوم ۳٫۹۵ شد چون ۰٫۹۵ گرمِ ماهِ قبل رویش نشست، و قسطِ چهارم ۲٫۷۴ شد چون ماهِ سوم ۰٫۲۶ گرم اضافه آمد.
همین قاعده در قسطِ ریالی (مثالِ ویدئو: ۶۵۴٬۱۱۹٬۰۳۰ ریال در ۴ قسط):
| قسط | مقرر | پرداخت |
|---|---|---|
| ۱ | ۱۶۳٬۵۲۹٬۷۵۸ | ۱۶۰٬۰۰۰٬۰۰۰ نقدی |
| ۲ | ۱۶۷٬۰۵۹٬۵۱۵ | ۵۰۰ دلار × ۴۴۰٬۰۰۰ = ۲۲۰٬۰۰۰٬۰۰۰ |
| ۳ | ۱۱۰٬۵۸۹٬۲۷۳ | ۹٫۳۲ گرمِ ۷۵۰ × ۲۴٬۴۹۳٬۰۰۰ = ۲۲۸٬۲۷۴٬۷۶۰ |
| ۴ | ۴۵٬۸۴۴٬۲۷۰ | — |
قاعدهٔ بقا: در هر لحظه «جمعِ پرداختشده + ماندهٔ اقساط = مبلغ کل». نه ریالی گم میشود نه اضافه — حتی اگر همهٔ اقساط کم یا زیاد پرداخت شده باشند.
#چهار شکلِ پرداخت
پنجرهٔ دریافت چهار دکمه دارد و هر کدام فیلدهای خودش را باز میکند:
| شکل | چه میگیری | نکته |
|---|---|---|
| پول | مبلغ + روش (نقدی / کارتخوان ـ حواله / چک) + حسابِ مقصد | معمولترین حالت |
| طلا و متفرقه | وزن و عیار (و شرح) | جنس واقعاً وارد مغازه میشود و در کاردکس مینشیند |
| سکه | تعداد + فیِ هر سکه | سکه هم واقعاً وارد میشود |
| ارز | مقدار + نرخ | مثلاً ۵۰۰ دلار × ۴۴۰٬۰۰۰ |
#مظنه: کِی خواسته میشود و کِی نه
مظنه فقط وقتی لازم است که واقعاً تبدیلی در کار باشد — یعنی وقتی جنسِ پرداختی روی محورِ بدهی نیست:
| بدهی | پرداخت | مظنه لازم است؟ |
|---|---|---|
| طلایی | پول / سکه / ارز | بله — باید به گرم تبدیل شود |
| طلایی | طلا و متفرقه | نه — وزنش مستقیم مینشیند |
| ریالی | پول / سکه / ارز | نه — خودش ریال است |
| ریالی | طلا و متفرقه | بله — باید به ریال تبدیل شود |
⚠ مظنهٔ پیشفرض، مظنهٔ امروز است، نه مظنهٔ قفلشدهٔ روزِ فروش. بدهیِ طلایی برای همین ساخته شد: مشتری باید طلا را به قیمتِ امروز حساب کند. اگر مظنه را دستی به قیمتِ روزِ فروش برگردانی، همان محافظتی را که با قسطِ طلایی خریده بودی خنثی کردهای.
#پیشنمایشِ زنده
پایینِ پنجره، پیش از هر ثبتی، این خطها زنده حساب میشوند:
- مقررِ همین قسط · تا حالا پرداختشده
- اعتبارِ این پرداخت (همان چیزی که از حسابِ مشتری کم میشود)
- ماندهٔ همین قسط
- مقررِ قسطِ بعد پس از این پرداخت ← همان عددی که در ویدئو با ماشینحساب گرفته میشود
- ماندهٔ کلِ اقساط
#چه سندی ساخته میشود
یک سندِ «دریافت» به نامِ همان مشتری، با یادداشتِ «قسط n از N — سند …»، که از همان اول به شمارهٔ قسط قفل است.
چرا گاهی دو سند میبینی؟ در قسطِ طلایی، ماندهٔ ریالیِ سندِ مشتری باید صفر بماند (بدهیاش طلاست، نه ریال). ولی همان لحظه واقعاً پول وارد کارتخوان شده. یک سند نمیتواند همزمان هر دو کار را بکند، پس برنامه یک سندِ سمتِ بانک جدا میسازد: سندِ مشتری طلا را کم میکند، سندِ بانک پول را وارد حساب میکند. در قسطِ ریالی چنین تضادی نیست و یک سند کافی است. همین منطق در وام و تسویهٔ کارتخوان هم به کار میرود → §۲۲ · §۸
سکه و طلایی که بابتِ بدهیِ ریالی میآید دو ردیف میسازد: یکی خودِ جنس (که وارد کاردکس میشود) و یکی ردیفِ «تهاتر» که همان جنس را از محورِ خودش برمیدارد تا مشتری بابتِ یک چیز دو بار بستانکار نشود. ردیفِ تهاتر کاغذی است و در ریز ورود ـ خروج و کاردکس دیده نمیشود — چون چیزی از در جابهجا نکرده.
#پنلِ «اقساطِ سررسیدشده» در صفحهٔ نخست
هر قسطی که سررسیدش رسیده یا گذشته و هنوز پرداخت نشده، همانجا فهرست میشود: کد، نام، تلفن، سررسید، مقررِ این قسط و ماندهٔ کلِ اقساط. سررسیدِ گذشته با رنگِ هشدار مشخص است.
- دکمهٔ کیفِ پول → مستقیم پنجرهٔ دریافت.
- دوبار کلیک روی سطر → سندِ فروشِ قسطیِ همان مشتری باز میشود.
#گزارش متمرکزِ حسابهای مدتدار در گزارشها
در صفحهٔ گزارشها، کارت حسابهای مدتدارِ باز تصویرِ یکجای همهٔ فروشهای قسطیِ تسویهنشده را نشان میدهد. این کارت برای پیگیری کلی ساخته شده و با پنل صفحهٔ نخست که فقط سررسیدهای رسیده را نشان میدهد فرق دارد.
سه شاخص بالای کارت:
- تعداد حسابهای مدتدارِ باز
- تعداد قسطهای عقبافتاده
- جمع ماندهٔ تعهدها با واحد واقعیِ همان قسط (ریال یا گرم ۷۵۰)
در جدول هر حساب، طرف حساب، ریالی یا طلایی بودن قسط، تعداد اقساط باز، مانده، سررسید بعدی و وضعیت عقبافتادگی دیده میشود. حسابهای عقبافتاده بالاتر میآیند تا کار وصول از همان ابتدا مشخص باشد. روی هر ردیف کلیک کنید تا سندِ فروشِ قسطی باز شود و دریافت را از جدول رسمیِ اقساط ثبت کنید.
ردیفهای قسط تعهدِ آیندهاند و ماندهٔ امروز را دوباره زیاد نمیکنند. گزارش از instSchedule میخواند؛ بنابراین پرداختشده، تتمّه و ماندهٔ جدول با کارت سند و پنل سررسیدها یک منبعِ حقیقت دارند.
#وضعیتِ ردیفهای قسط در سند
| نشان | یعنی |
|---|---|
| تسویه شد | پرداختِ کاملِ همان قسط |
| تتمّهٔ … به قسط n رفت | قسط بسته شد ولی کم/زیاد آمد و اختلافش منتقل شد |
| مانده … | هنوز پرداختی روی این قسط ننشسته |
| سررسید گذشته | تاریخش رد شده و باز است |
#اشتباهِ رایج
- ثبتِ دریافتِ قسط با سندِ دستیِ «دریافت». آن سند مانده را درست میکند ولی جدولِ اقساط از آن بیخبر میماند: نه قسطی تسویه میشود، نه تتمّهای جابهجا. همیشه از همین پنجره ثبت کن.
- ضمانت را پرداختِ قسط حساب کردن. چک یا طلای ضمانت پرداخت نیست → سندِ امانات جدا. §۱۰
- دستکاریِ مبلغِ ردیفِ قسط برای «درستکردنِ» عدد. لازم نیست؛ تتمّه خودش جابهجا میشود.
#ربط این بخش به بقیهٔ راهنما
| موضوع | کجا |
|---|---|
| ساختنِ خودِ نقشهٔ قسط | §۳۷ |
| حسابِ بانکی و کارتخوان | §۸ |
| چکِ دریافتی و سررسیدش | §۲۸ |
| کاردکسِ جنسی که بابتِ قسط آمده | §۲۷ |
| ریز ورود و خروج | §۲۵ |
| امانات و ضمانت | §۱۰ |
#۳۹. انتقال سند: ابزار قیچی
کجاست: صفحهٔ سند ← منوی سهنقطه کنارِ نامِ شخص ← «انتقال سند» (آیکونِ قیچی ✂).
سندی را که باید برای «احسان حاجیصفی» میزدی، اشتباهی روی «ایرج طهماسب» ثبت کردهای. ردیفها درستاند؛ فقط زیرِ نامِ اشتباهی نشستهاند. انتقال سند همین یک کار را میکند: سند را از حسابِ اول برمیدارد و بیکموکاست زیرِ نامِ شخصِ دوم مینشاند.
#کارِ غلطی که وسوسهکننده است
سند را حذف کنی و ردیفها را از نو زیرِ نامِ درست تایپ کنی — «دریافت سرویس شایان»، «دریافت انگشتر زیتون»، «دریافت دستبند رولکس» و بعد هم اجرتها. کارِ تکراری، و هر بار یک فرصتِ تازه برای اشتباهِ تایپی.
«حذف سند» برای این کار نیست. حذف مالِ سندی است که اصلاً نباید ثبت میشد — نه برای این شخص، نه برای آن یکی. اگر ردیفها درستاند و فقط طرفِ حساب عوضی است، حذف نکن؛ قیچی بزن.
#روالِ کار
| گام | کار |
|---|---|
| ۱ | سندِ اشتباه را باز کن |
| ۲ | منوی سهنقطه ← انتقال سند (✂) |
| ۳ | پیام میآید: «سند حذف میشه و منتقل میشه به حساب شخصی دیگر. ادامه میدی؟» → انتقال |
| ۴ | شخصِ مقصد را انتخاب کن — از لیست، یا اسمش را در کادرِ جستوجو بنویس و Enter |
سند در حسابِ مبدأ برداشته میشود و در حسابِ مقصد با شمارهٔ سندِ تازه مینشیند. کدِ سند همان میماند. در مثالِ ویدئو: سندِ ۱ از ایرج طهماسب (کد ۱۲۸) شد سندِ ۵ در احسان حاجیصفی (کد ۱۲۶)، با همان کدِ سندِ ۲۴۸.
#⚠ چه چیزی میرود و چه چیزی نمیرود
ردیفها، تشخیص، شرح، وزن و عیار عیناً منتقل میشوند. اما اجرت و فی منتقل نمیشوند — از نو، از دفترِ فیِ شخصِ مقصد خوانده میشوند.
دلیلش ساده است: اجرتِ یک جنس عددِ ثابتِ جهانی نیست؛ با هر طرفِ حساب فرق دارد. کیمیا برای هر شخص، آخرین فیِ دریافتیِ هر جنس را نگه میدارد و دفعهٔ بعد که همان جنس را از همان شخص میگیری، خودش همان را میگذارد تا کارت راحت شود. بعد از انتقال هم دقیقاً همین اتفاق میافتد — یعنی اعدادِ سندِ مقصد، اعدادِ آن شخص است، نه اعدادی که خودت در سندِ اول تایپ کرده بودی.
مثالِ واقعی (کدِ سندِ ۲۴۸):
| ردیف | وزن | عیار | ٪ نزد طهماسب | وزن ۷۵۰ | ٪ نزد حاجیصفی | وزن ۷۵۰ |
|---|---|---|---|---|---|---|
| سرویس شایان | ۴۹٫۷۵ | ۷۵۰ | ۵ | ۵۲٫۲۴ | ۷ | ۵۳٫۲۳ |
| انگشتر زیتون | ۲۲٫۰۰ | ۷۵۰ | ۱۲ | ۲۴٫۶۳ | ۹ | ۲۳٫۹۸ |
| دستبند رولکس | ۶۹٫۷۷ | ۷۵۰ | ۱۰ | ۷۶٫۷۵ | — | ۶۹٫۷۷ |
| ۱۵۳٫۶۳ | ۱۴۶٫۹۸ |
ماندهٔ سند بعد از انتقال ۱۵۳٫۶۳ نماند، شد ۱۴۶٫۹۸ — نه چون چیزی گم شده، بلکه چون اجرتها با اعدادِ حاجیصفی بازخوانی شدهاند.
#وقتی جنس نزدِ آن شخص سابقه ندارد
ردیفِ سوم اجرتش خالی ماند، چون دستبند رولکس تا امروز از حاجیصفی دریافت نشده بود و در دفترِ فیِ او هیچ فیِ دریافتیای بابتِ این جنس ثبت نیست. چیزی خراب نشده؛ فقط کیمیا حدس نمیزند. عدد را خودت بزن — در ویدئو ۱۰٪ زده شد و وزنِ ۷۵۰ همان ۷۶٫۷۵ برگشت و ماندهٔ سند ۱۵۳٫۹۶ شد (ماندهٔ نهاییِ حاجیصفی از ۳۰۵٫۸۱ رفت روی ۳۱۲٫۷۹).
ردیفی که اجرتش خالی است، مبلغِ ریالی هم نمیسازد. تا پُرش نکنی، آن ردیف در ماندهٔ ریالی سهمی ندارد.
#چکلیستِ بعد از هر انتقال
- ستونِ ٪ و فیِ تکتکِ ردیفها را نگاه کن — این تنها چیزی است که عوض میشود.
- ردیفهایی که خالی ماندهاند را دستی پر کن.
- ماندهٔ سند و ماندهٔ نهایی را با چیزی که انتظار داشتی بسنج.
جمعِ بندی: اگر ردیفهای یک سند را برای شخصِ اشتباهی ثبت کردی، بهجای حذف و تایپِ دوباره، از انتقالِ سند (قیچی) استفاده کن — و بعدش اجرتها را چک کن.
#انتقال بین دفترها: وقتی اسم را در گروهِ اشتباه ساختهای
حالتِ بالا وقتی بود که هر دو شخص در یک دفتر هستند. اما گاهی کلِ حسابِ یک مشتری را در دفترِ اشتباه ساختهای — مثلاً «خانم طهماسب» را که مشتریِ تکفروشی است، اشتباهی در بنکداری تعریف کردهای و چند فاکتور هم برایش زدهای. حالا میخواهی اسم و فاکتورهایش بروند به تکفروشی.
خودِ شخص را نمیشود قیچی کرد. کیمیا عمداً اجازهٔ بریدنِ یک اسم از گروهی و چسباندنش به گروهِ دیگر را نمیدهد؛ چون ریسکِ اشتباه بالاست. اسم را باید در گروهِ مقصد از نو بسازی؛ ولی فاکتورها را میشود منتقل کرد.
چرا اینقدر سختگیری؟ چون هر گروه ستونها و منطقِ خودش را دارد (پایینِ همین بخش، «چرا فقط یکطرفه»). به همین دلیل هم گزینههای پرخطر مثل «حذف سند» و «انتقال سند» سرِ دست نیستند، کلید میانبر ندارند و موقعِ حذف یک انیمیشنِ هشدار نشان داده میشود — تا اشتباهِ بیبازگشت پیش نیاید.
#اول، اسم را در گروهِ مقصد بساز
اگر همان اسم را مستقیم در تکفروشی بزنی و Enter کنی، خطا میگیری: «مشابهِ این در سیستم موجود است» — چون همان اسم در گروهِ دیگری (بنکداری) هست. دو راه داری:
- اسم را کمی متفاوت کن: در بنکداری روی اسم برو و چیزی به آن اضافه کن (مثلاً «خانم طهماسبی ۱»)، بعد در تکفروشی اسمِ اصلی را دوباره بساز.
- ساختِ حسابِ جدید با تأییدِ تکراری: در هر گروهی که باشی، از سمت چپِ برنامه دکمهٔ + سبز (یا کلید
Alt++) را بزن، گروهِ تکفروشی را انتخاب کن؛ یک سندِ بینام ساخته میشود که نامش با رنگِ آبی مشخص است. کافی است تایپ کنی یاCtrl+Vبزنی تا نامِ موردنظر جایگزین شود. وقتی هشدارِ «اسمِ مشابه در سیستم داری» آمد، چون خودت میدانی، تأیید کن.
#بعد، فاکتورها را منتقل کن — دو حالت
| حالت | مناسبِ | روش |
|---|---|---|
| انتقالِ تکتکِ اسناد | وقتی اسناد کم است | در سندِ بنکداریِ شخص، از اولین سند: ویرایش ← سهنقطه ← انتقال سند ← به تکفروشی، همان شخص. برای سرعت، کدِ اشخاص را حفظ کن و موقعِ انتخابِ مقصد کد را تایپ کن و Enter. سندها یکییکی میروند. |
| حواله کردنِ مانده | وقتی اسناد زیاد است (مثلاً ۷۰ سند) | انتقالِ تکتک وقتگیر و پرخطاست. بهجایش در سندِ شخص در بنکداری، کلِ ماندهحساب را با یک حواله به حسابِ همان شخص در تکفروشی بفرست. مانده به دفترِ مقصد منتقل میشود و حسابِ مبدأ صفر میشود. |
بعد از خالیشدنِ حساب در گروهِ مبدأ، دیگر لازم نیست اسمِ قدیمی جلوی چشم بماند. اگر سندی برایش ثبت شده و میخواهی تاریخِ اسناد حفظ شود، حذفش نکن؛ به اسمِ شخص برو، پایین بیا و وضعیت نمایش را روی مخفی بگذار. اسم به قسمتِ «مخفیها» میرود و از لیستِ گروه بیرون میآید بیآنکه پاک شود. (برای حواله، §۹.)
#ربط این بخش به بقیهٔ راهنما
| موضوع | کجا |
|---|---|
| سند و ردیفهایش | §۳ |
| ستون تشخیص (دریافت/پرداخت) | §۴ |
| وزن ۷۵۰ و اثر اجرت رویش | §۶ |
| مانده و بدهکار/بستانکار | §۲ |
| نوار پایین صفحه و ماندهٔ سند | §۳۴ |
| کار با چند سربرگِ همزمان (برای مقایسهٔ مبدأ و مقصد) | §۲۳ |
#۴۰. جستجوی هوشمند: پیدا کردن شخص، جنس و سند
جستجو جایی است که در طولِ روز بیشترین بار را میکشد. فرضِ این بخش یک چیز است: فروشنده وقتِ تایپِ کامل ندارد و اغلب هم یادش میرود زبانِ کیبورد را عوض کند.
#نوارِ جستجوی بالای صفحه
هر چیزی که بزنی، در همهٔ اینها همزمان میگردد:
| میزنی | پیدا میکند |
|---|---|
۱۴۵ | شخصی که کدش ۱۴۵ است |
۰۹۱۲… | شخص با شمارهٔ تلفن |
جهانبخش | تکهای از نام |
| کد ملی | شخصِ صاحبِ آن کد ملی |
ع ج یا عج | حروفِ اول → علیرضا جهانبخش (فاصله لازم نیست) |
| کدِ یک سند | صاحبِ آن سند |
نتیجهها مرتب میآیند: تطبیقِ دقیق بالاتر از تطبیقِ ابتدای نام، و آن بالاتر از تطبیقِ وسطِ نام.
#وقتی کیبورد انگلیسی مانده است
این را جدی بگیر چون روزی دهها بار پیش میآید. کافی است همانطور که هست تایپ کنی — پنل خودش حدس میزند که منظورت فارسی بوده:
تایپ میکنی: ug → میفهمد: عل → علیرضا، علیاکبر، …
تایپ میکنی: ns → میفهمد: دس → دستبند، دستبند لوکس، …
نگاشت، همان چیدمانِ استانداردِ فارسی است: حرفی که روی همان کلیدِ فیزیکی نشسته. کلیدهای علامتیشکل هم حساب میشوند ([ = ج، ] = چ، ; = ک، ' = گ، , = و).
این حدس جایگزینِ جستجوی لاتین نمیشود، اضافه بر آن است. اگر واقعاً دنبالِ یک نامِ انگلیسی یا بارکد باشی، هر دو خوانش سنجیده میشوند و هرکدام نتیجهٔ بهتری داد برنده است.
#ستونِ «شرح» در ردیفِ سند
قبلاً فهرستِ پیشنهادِ نامِ کالا فهرستِ بومیِ مرورگر بود و فقط از ابتدای رشته تطبیق میداد — «دبند» هیچوقت «دستبند» را نمیآورد. حالا همان موتورِ جستجوی بالا اینجا هم کار میکند:
| میزنی | میآورد |
|---|---|
د ب | دستبند بچگانه (حروفِ اول) |
دبند | دستبند (تکهٔ وسطِ نام) |
دست بند | دستبند (فاصله در فارسی سلیقهای است) |
ns | دستبند، دستبند لوکس (کیبورد انگلیسی) |
- با کلیدهای بالا/پایین بینِ پیشنهادها حرکت کن و با Enter انتخاب کن؛ Esc فهرست را میبندد.
- در سندِ مرجوعی فهرست فرق میکند: فقط اجناسی که به همین شخص فروختهای پیشنهاد میشود، نه کلِ کاتالوگ. (بخش ۳۵)
- انتخاب از فهرست دقیقاً همان مسیرِ تایپِ دستی را میرود؛ عیار و فیِ پیشفرضِ آن قلم مثل همیشه پر میشود.
#ذرهبین: «جستجوی کد سند»
مشتری با فاکتورِ چاپی میآید و میخواهد جنس را پس بدهد. کدِ روی فاکتور را در نوارِ بالا بزن و بهجای Enter، روی ذرهبین کلیک کن:
| کاری که میکنی | نتیجه |
|---|---|
| Enter | فهرستِ اشخاصِ مرتبط (کارِ همیشگی) |
| کلیک روی ذرهبین | خودِ همان فاکتور برای ویرایش باز میشود |
اینجا تطبیق عمداً برابرِ دقیق است، نه فازی — سندِ اشتباه باز کردن بدتر از پیدا نکردن است. اگر کدی با آن شماره نباشد پیام میدهد و چیزی باز نمیکند.
#اشتباهِ رایج
- «چرا جستجوی جنس، شخص نمیآورد؟» چون فهرستِ ستونِ شرح فقط در کاتالوگِ کالا میگردد. جستجوی شخص جای دیگری است: نوارِ بالای صفحه.
- «زدم ولی چیزی نیامد.» اگر عبارت خیلی کوتاه است (یک حرف)، حالتِ حروفِ اول فعال نمیشود؛ دستِکم دو حرف بزن.
#ربط این بخش به بقیهٔ راهنما
#۴۱. سنگ و نگین: انگشتر یاقوت، عقیق و فیروزه
انگشتر و آویزِ نگیندار دو قیمت دارد که با هم جمع میشوند: قیمت طلا و قیمت سنگ. دکمهٔ 💎 کنارِ نامِ کالا در ردیفِ طلا، پنجرهٔ «سنگ و نگین» را باز میکند.
#قاعدهٔ اول: وزنِ لیبل، وزنِ طلاست
بنکدار روی لیبلِ هر انگشتر فقط وزن طلا را میزند و وزن سنگ هم کسر شده است. شما جعبه را باز نمیکنید و سنگ را جدا وزن نمیکنید — به همان لیبلی که به کالا متصل است اعتماد میکنید.
نتیجهٔ این قاعده در برنامه یک خط است:
سنگ وزن نیست، مبلغ است.
یعنی ستونِ «وزن» ردیف دستنخورده همان وزنِ طلاست، گرمِ ۷۵۰ و ماندهٔ طلاییِ مشتری از سنگ تکان نمیخورد، و سنگ فقط به مبلغ ردیف اضافه میشود.
اگر لیبلی وزنِ ناخالص داشت (طلا + سنگ با هم)، خانهٔ «وزن کل» را پر کنید؛ برنامه وزن سنگ را کسر میکند و وزن طلا را خودش مینویسد.
#سه روش محاسبهٔ مبلغ سنگ
| روش | فرمول | کِی |
|---|---|---|
| فی سنگ × وزن سنگ | فی هر قیراط (یا گرم) × وزن کل سنگ | سنگِ قیمتی که وزنی خریدهای — یاقوت، زمرد |
| فی سنگ × تعداد سنگ | فی هر دانه × تعداد | نگینهای هماندازه که دانهای قیمت خوردهاند |
| فقط مبلغ سنگ | همان عددی که روی لیبل خورده | وقتی بنکدار فقط یک مبلغ داده — رایجترین حالت |
مثال ویدئو — «انگشتر نگین عقیق و فیروزه»، ۱۲ عدد. لیبلها را جمع میکنی و روشِ «فقط مبلغ سنگ» را میزنی: ۸۴٬۵۰۰٬۰۰۰ ﷼. وزن طلا جدا در ستونِ وزن نشسته است.
#قیراط و دلار
سنگ میتواند واحدِ وزنِ خودش را داشته باشد و پولش ارزِ دیگری باشد — «یاقوتش قیراطی است اما پولش دلاری است».
- واحد وزن: قیراط یا گرم. هر قیراط ۰٫۲ گرم است؛ تبدیل فقط برای بیرونکشیدنِ وزن طلا از وزن کل به کار میرود، نه برای قیمت.
- ارز: تومان یا دلار (نرخ زنده). مبلغِ دلاری با نرخِ روزِ دلار ریالی میشود — همان قاعدهٔ اجرتِ دلاری. کار را دلاری خریدهای، ولی پولش را ریالی از مشتری میگیری.
کنارِ مبلغِ سنگ در ستونِ مبلغِ ردیف، نشانِ $ میآید تا بدانی این عدد از دلار آمده است.
#ماشینحسابِ خودکار: هر خانه را پر کنی، بقیه میآید
پنجره هفت خانهٔ بههمبسته دارد:
| خانه | واحد |
|---|---|
| وزن کل (طلا + سنگ) | گرم |
| وزن طلا (لیبل) | گرم |
| وزن کل سنگ | قیراط / گرم |
| وزن یکدانه | قیراط / گرم |
| تعداد سنگ | دانه |
| فی سنگ | تومان / دلار |
| قیمت کل سنگ | تومان / دلار |
هرچه داری بزن و دکمهٔ «محاسبه — خانههای خالی را پر کن» را بزن. سه رابطهٔ ساده پشتِ کار است و پشتسرهم اجرا میشوند تا زنجیره تا ته باز شود:
وزن کل = وزن طلا + وزن سنگ
وزن کل سنگ = تعداد × وزن یکدانه
قیمت کل سنگ = فی × (وزن سنگ یا تعداد)
مثال ویدئو — یاقوت. سه عدد داری:
| میزنی | برنامه درمیآورد |
|---|---|
| وزن کل ۱۳٫۴۹ گرم | وزن طلا ۱۲٫۹۷ گرم (۱۳٫۴۹ − ۲٫۶×۰٫۲) |
| وزن سنگ ۲٫۶ قیراط | فی هر قیراط ۱۹۲٫۳۱ دلار (۵۰۰ ÷ ۲٫۶) |
| قیمت کل ۵۰۰ دلار |
خانههایی که برنامه پر کرده طلایی میشوند تا از عددهای خودت جدا باشند. اگر روی خانهای دست بزنی، نشانِ طلاییاش میرود — یعنی از این به بعد آن عدد مالِ توست و دیگر بازنویسی نمیشود.
خانههایی که خودت پر کردهای هرگز دستکاری نمیشوند. «محاسبه» فقط خانههای خالی را مینویسد.
#سنگ در فرمول سود و مالیات
سنگ کنارِ اجرت مینشیند، نه کنارِ طلای خام. دلیلش ساده است: طلای خام از ارزش افزوده معاف است، سنگ نیست.
سود تکفروشی = (طلای خام + اجرت + سنگ) × ٪سود ارزش افزوده = (اجرت + سنگ + سود تکفروشی) × ٪مالیات
در کارتِ مالیاتِ پایینِ سند، سطرِ «سنگ و نگین» بینِ اجرت و سود اضافه میشود و در جمعِ کلِ فاکتور هم میآید. روی فاکتورِ چاپی هم همین سطر مینشیند.
مثال — انگشترِ نگین، وزن طلا ۱۰ گرمِ ۷۵۰، قیمت طلا ۱۵٬۰۸۹٬۰۰۰، اجرت ۲۰٪، سنگ ۸۴٬۵۰۰٬۰۰۰، سود ۷٪، مالیات ۹٪:
| لایه | مبلغ |
|---|---|
| طلای خام (۱۰ × ۱۵٬۰۸۹٬۰۰۰) | ۱۵۰٬۸۹۰٬۰۰۰ |
| اجرت ۲۰٪ | ۳۰٬۱۷۸٬۰۰۰ |
| سنگ و نگین | ۸۴٬۵۰۰٬۰۰۰ |
| سود تکفروشی ۷٪ روی هر سه | ۱۸٬۵۸۹٬۷۶۰ |
| مالیات ۹٪ روی (اجرت + سنگ + سود) | ۱۱٬۹۹۴٬۰۹۸ |
| جمع فاکتور | ۲۹۶٬۱۵۱٬۸۵۸ |
اگر همین ردیف معاف باشد (تیکِ «ارزش افزوده دارد» برداشته شده)، سنگ هم مثل اجرت از پایهٔ مالیات کنار میرود ولی از پایهٔ سود کنار نمیرود — دقیقاً همان قاعدهٔ §۳۶.
#⚠ مبلغ سنگ را از روی لیبل بزن، نه بیشتر
وسوسهانگیز است که سودِ سنگ را همانجا داخلِ «قیمت کل سنگ» بگذاری. نگذار:
اگر پول سنگ را گرانتر از لیبل وارد کنی، موجودیِ ریالیِ سنگی که در ویترین داری با موجودیِ واقعی نمیخواند.
مثال: ۱۲ انگشتر گرفتهای که سنگش رویِهم ۸۴۵ هزار تومان پای خودت افتاده. یکی را میفروشی و سنگش را ۱۰۰ هزار تومان میزنی، در حالی که سهمش ۵۰ هزار تومان بوده. برنامه ۷۴۵ هزار تومان سنگِ باقیمانده نشان میدهد، ولی واقعاً ۷۹۵ هزار تومان سنگ داری. آن ۵۰ هزار تومان سودِ توست، نه سنگ.
پس سود سنگ را کجا بگذاریم؟ دو جای درست دارد:
- روی اجرت ردیف اضافهاش کن، یا
- روی سود فروشنده (درصدِ سودِ همان سند) بگذارش.
این هشدار فقط برای روشِ «فقط مبلغ سنگ» است. در دو روشِ دیگر (فی × وزن یا فی × تعداد) برنامه میداند چقدر پای خودت افتاده و چقدر موجود است، خودش میانگین میگیرد و سود را جدا از قیمتِ کلِ سنگ حساب میکند.
#پیشفرض سنگ در تعریف جنس
در تعریف جنس، تیکِ «سنگدار» یک بخش باز میکند:
| فیلد | برای چه |
|---|---|
| نام سنگ | یاقوت، فیروزه، عقیق… |
| واحد وزن سنگ | قیراط یا گرم |
| ارز سنگ | تومان یا دلار (نرخ زنده) |
| روش محاسبهٔ مبلغ سنگ | یکی از سه روش بالا |
از آن به بعد هر بار این جنس در سند بیاید، ردیف با همین پیشفرضها آماده میشود و فقط عددها را میزنی. اگر ردیف از قبل سنگ داشته باشد، دست نمیخورد.
#مادهٔ همراه: چرم، بند، مینا، نخ و کنف (v34)
دستبندِ چرم هم چرم دارد هم طلا — و این دو یکی نیستند:
اجرتِ چرمش جدای اجرتِ طلاست. چیزی که بازار فهمیده این است که پولِ چرم قاطیِ پولِ طلا نمیشود؛ جدا حساب میکنند.
همان دکمهٔ 💎 این کار را هم میکند. بالای پنجره یک انتخابِ دوتایی آمده:
| گزینه | برای چه |
|---|---|
| نگین و سنگ قیمتی | یاقوت، فیروزه، عقیق — با وزن و قیراط و فی و حلکننده |
| مادهٔ همراه | چرم، بند، نخ و کنف، مینا، رزین، صدف، چوب، سرامیک، کریستال، ابریشم |
انتخابِ «مادهٔ همراه» پنجره را کوچک میکند، و این عمدی است. مادّه نه قیراط دارد، نه فیِ هر دانه، نه «وزن کل منهای وزن طلا». فقط دو چیز لازم است:
- نام مادّه — از فهرستِ آماده انتخاب کن یا هرچه میخواهی بنویس
- قیمت کل — همان مبلغی که پای خودت افتاده
خانههای وزن و واحد و روشِ محاسبه و دکمهٔ «محاسبه» پنهان میشوند، چون هیچکدام دربارهٔ چرم معنا ندارند.
بقیهٔ برنامه نامِ مادّه را یاد میگیرد. جایی که برای نگین «سنگ» مینوشت، حالا برای این ردیفها «چرم» مینویسد:
| کجا | نگین | مادّه |
|---|---|---|
| زیرِ مبلغِ ردیفِ سند | سنگ ۸۴۵٬۰۰۰ | چرم ۱۱۰٬۰۰۰ |
| کارت مالیات پایینِ سند | سنگ و نگین | چرم |
| فاکتور چاپی | سنگ و نگین | چرم |
اگر یک سند هم چرم داشته باشد هم بند، میشود «چرم / بند». اگر هم نگین داشته باشد هم چرم، میشود «سنگ و چرم».
مادّه هم مثل نگین وزن نیست، مبلغ است. گرمِ ۷۵۰ِ ردیف را تکان نمیدهد و ماندهٔ طلاییِ مشتری دستنخورده میمانَد. در فرمول سود و مالیات هم دقیقاً جای سنگ مینشیند: کنارِ اجرت، نه کنارِ طلای خام.
#⚠ مادّه را به قیمت خرید بفروش — سودش را جای دیگر بگذار
همان هشدارِ سنگ، اینجا جدیتر است، چون مادّه معمولاً چند تایی خریده میشود و تکتک فروخته:
مثالِ واقعی — پنج دستبند چرم از یک همکار گرفتهای، هرکدام ۱۱۰٬۰۰۰ ﷼ چرم، جمعاً ۵۵۰٬۰۰۰ ﷼. یکی را میفروشی. اگر همان ۱۱۰٬۰۰۰ را بزنی، مانده میشود ۴۴۰٬۰۰۰ ﷼ — یعنی چهار بند چرم، درست. اما اگر ۱۶۰٬۰۰۰ بزنی که ۵۰٬۰۰۰ سود کرده باشی، مانده میشود ۳۹۰٬۰۰۰ ﷼، در حالی که واقعاً ۴۴۰٬۰۰۰ چرم در کشو داری.
سودِ مادّه را روی اجرت یا سود فروشنده بگذار، نه روی خودِ مادّه. آنوقت هم سود را گرفتهای، هم ماندهٔ چرم درست مانده.
عملاً: مبلغِ نهاییِ فاکتور را ۵۰٬۰۰۰ بالاتر بزن. آن ۵۰٬۰۰۰ در «سود مغازه» مینشیند و ماندهٔ چرم دستنخورده میمانَد.
برنامه همان لحظهٔ ورود این را میگوید: تا مبلغی میزنی که با میانگینِ خریدِ همان مادّه بیش از ۲٪ فرق دارد، زیرِ فرم یک هشدار میآید و میگوید میانگینِ خرید چقدر بوده. زیرِ ۲٪ چیزی نمیگوید، چون آنقدرش از گِرد کردن و چانهزنیِ معمول میآید.
#ماندهٔ موادِ همراه
در کالا و انبار ← موجودی اجناس، زیرِ جدولِ اصلی جدولِ «ماندهٔ موادِ همراه» آمده:
| مادّه | وارد شده | خارج شده | میانگین خرید | مانده |
|---|---|---|---|---|
| چرم | ۵۵۰٬۰۰۰ (۵ ردیف) | ۱۱۰٬۰۰۰ (۱ ردیف) | ۱۱۰٬۰۰۰ | ۴۴۰٬۰۰۰ |
چرم و بند و مینا ردیفِ جداگانهٔ انبار ندارند — روی همان ردیفِ طلا سوارند. پس این جدول دستی نیست؛ از خودِ اسناد ساخته میشود و هر بار که سندی ثبت میکنی خودش بهروز است.
کارش این است: مانده را با شمارشِ واقعیِ کشو بسنج. اگر نخواند، جایی مبلغِ فروش را بالاتر از خرید زدهای — همان اشتباهی که بالا توضیح داده شد.
#ربط این بخش به بقیهٔ راهنما
| موضوع | کجا |
|---|---|
| فرمول سهلایهٔ مبلغ و کارت مالیات | §۷ |
| معافیت ارزش افزودهٔ ردیفی | §۳۶ |
| اجرت دلاری و نرخ زندهٔ دلار | §۷ |
| مرجوعی و پسدادن سهمِ سود و مالیات | §۳۵ |
| تعریف جنس و عکس اجناس | §۱۷ |
#۴۲. دفتر روزانه: کارِ امروز، ردیفبهردیف
صفحهٔ «دفتر روزانه» در منوی کناری، زیر گروهِ «سایر». نیاز به دسترسی daybook دارد.
#چرا این گزارش با بقیه فرق دارد
همهٔ گزارشهای دیگر یک موضوع دارند: کاردکس گردشِ یک قلم را میگوید، دفتر چک یک برگه را، حساب شخص یک نفر را. دفتر روزانه موضوع ندارد — یک برشِ زمانی است:
هرچه در این بازه ثبت شده، ردیفبهردیف، پشتِ سرِ هم.
کاربردش دقیقاً همان چیزی است که آخر وقت لازم داری: «امروز چه کار کردم؟» تکفروشی، آبشدهای که به بنکدار دادی، حوالهای که زدی، سکهای که خردهفروشی کردی، هزینهای که بابت مغازه پرداختی — همه در یک لیست.
#بازهٔ زمانی
یک فهرست بالای صفحه، با همان گزینههایی که در کار روزانه لازم میشود:
| گزینه | یعنی |
|---|---|
| فقط امروز | پیشفرض — کارِ همین امروز |
| از دیروز | دیروز و امروز |
| از یک هفته پیش | هفت روز اخیر |
| از یک ماه پیش | سی روز اخیر |
| از ۶ ماه پیش | نیمسال اخیر |
| از اول این برج | از روز یکمِ ماه جاری |
| از ابتدای دوره | همهٔ اسناد، بدون کران |
| دستی | دو خانهٔ «از» و «تا» باز میشود و خودت تاریخ میزنی |
بازهٔ فعال همیشه بهصورت متن کنارِ فهرست نوشته میشود، تا هیچوقت به عددی نگاه نکنی که ندانی مالِ چه بازهای است.
#ستونهای جدول
| ستون | چه میگوید |
|---|---|
| ☰ | شمارهٔ ردیفِ گزارش (نه شمارهٔ سند) |
| کد سند | کدِ سراسریِ فاکتور؛ روی همهٔ ردیفهای یک سند تکرار میشود |
| تاریخ | تاریخ سند |
| سند | فاکتورِ چندمِ همان طرف حساب است — مستقل از کد سراسری |
| شرح | دو خط: نام طرف حساب (آبی = دریافتی، قرمز = پرداختی) و زیرش شرح ردیف با کد شرح، عیار و تشخیص |
| وزن | وزنِ روی ترازو (برای سکه: تعداد) |
| وزن ۷۵۰ دریافتی | طلایی که وارد مغازه شده |
| وزن ۷۵۰ پرداختی | طلایی که از مغازه خارج شده |
| مبلغ دریافتی | ریالی که وارد شده |
| مبلغ پرداختی | ریالی که خارج شده |
| ارز | واحد آن خط: طلا، ریال، سکه، یا ارزِ غیرریالی با مبلغش |
زیر جدول برای هر واحد یک سطرِ جمع میآید: جمع . طلا ، جمع . ریال ، جمع . سکه و برای هر ارزِ غیرریالی یک سطرِ جدا.
چرا دو ستون بهجای یک ستونِ علامتدار؟ چون مغازهدار نمیخواهد منفی و مثبت را از هم تشخیص بدهد؛ میخواهد ببیند چه آمد و چه رفت. جهت از همان rowMult میآید که ماندهٔ حسابها را میسازد، پس «مرجوع» و ورود/خروجِ مطلق خودبهخود در ستونِ درست مینشینند.
#جمعِ این گزارش دقیقاً با ماندهٔ حسابها میخوانَد
این مهمترین تضمینِ دفتر روزانه است. سود فروشنده و ارزش افزودهٔ فاکتورهای مالیاتدار خطِ جداگانهٔ خودش را میگیرد با برچسب «سود فروشنده و ارزش افزوده». اگر این خط نبود، جمعِ ریالیِ دفتر روزانه با مجموعِ تغییرِ ماندهٔ اشخاص فرق میکرد و ساعتها دنبال اختلافی میگشتی که اصلاً وجود ندارد.
#دو حالتِ گزارش
«هر چی که هست» — پیشفرض. هیچ فیلتری اعمال نمیشود؛ کارِ بازه به ترتیبِ تاریخ میآید.
«به انتخاب خودم» — پنلِ فیلتر باز میشود، پنج کارت کنارِ هم. هر کارت جستوجوی خودش را دارد و دو دکمهٔ «همه» و «هیچ». کارتی که چیزی در آن انتخاب نشده باشد یعنی «همه» — پس فیلترها روی هم جمع میشوند، نه اینکه هم را خنثی کنند.
| کارت | چه چیزی را محدود میکند |
|---|---|
| شخص | یک یا چند طرف حساب — یا با زبانهٔ «گروه»، یک گروهِ حساب کامل (بنکدار، تکفروشی، آبشده فروش…) |
| جنس | زبانهٔ «قلم» (همان قلمهای گردش موجودی)، «گروه جنس» (آبشده، متفرقه، جنس، سکه) یا «شرح» (کدهای ۱ تا ۱۰). خانهٔ محدود به عیار هم همینجاست |
| انتخاب ویژه | حواله · کارتخوان · چک · سکه · ارز · امانت تعمیر · قسطی · مالیاتدار · مرجوعی · سنگدار |
| ارز و ردیف | واحد (طلا/ریال/سکه/ارز) · جهت ردیف (دریافتی/پرداختی) · نوع سند (فروش، خرید، دریافت، پرداخت، سایر) |
| کاربر ثبتکننده | «امروز آقای فلانی چه اسنادی ثبت کرده؟» — فهرست از خودِ اسناد ساخته میشود |
مثالهای واقعی: «هر چه حواله داریم از ابتدای دوره» · «هر چه کارتخوان کشیده شده» · «امروز کاربر پویا چه ثبت کرده» · «فقط دریافتها» · «فقط عیار ۷۴۰».
#دو کلیدِ نمایش
خلاصه — روشن که باشد، هر فاکتور در یک ردیف چاپ میشود. خاموش که باشد، فاکتورها ردیفبهردیف میآیند. فاکتوری که دو ردیف دارد در حالت خاموش دو خط است و در حالت روشن یک خط.
چاپ درصدها در ردیف جدا — اجرت (و مبلغ سنگ) از مبلغِ خودِ ردیف کنده میشود و خطِ جداگانهای با عنوان «دریافت/پرداخت بابت درصد» میگیرد. مثالِ یک فاکتورِ دو ردیفی:
| خط | مبلغ |
|---|---|
| سرویس زر (بدون اجرت) | مبلغ طلای خام |
| پرداخت بابت درصد | اجرتِ ۱۵٪ همان ردیف |
| النگو شمش (بدون اجرت) | مبلغ طلای خام |
| پرداخت بابت درصد | اجرتِ ۱۰٪ همان ردیف |
جمعِ کل با روشن و خاموشبودنِ این کلید ذرهای فرق نمیکند — فقط تفکیک میشود. این را تست قفل کرده است.
#جستوجو، کلیدهای میانبر و نشانگذاری
- جستوجو در هر دو حالت کار میکند و روی محتوای همهٔ ستونها است: کد سند، تاریخ، نام شخص، شرح، مبلغ و وزن. مثال ویدئو: «النگوی شمش را از چه کسانی گرفتم و به چه اشخاصی دادم؟»
- کلید F هر جای صفحه که باشی مستقیم میبَرَدت سرِ جعبهٔ جستوجو.
- روی یک ردیف کلیک کن و Space بزن: آن ردیف نشاندار میشود. اینطور میدانی تا کجای کارِ امروز را بررسی کردهای. نشانها در مرورگرِ خودت میمانند و با «پاککردن نشانها» یکجا برداشته میشوند.
- Enter یا دابلکلیک روی ردیف، همان سند را برای ویرایش باز میکند.
#کِی از این گزارش استفاده نکن
اگر دنبالِ گردشِ یک قلمِ مشخص هستی، §۲۷ گردش موجودی راحتتر است. اگر دنبالِ یک چکِ خاص هستی، §۲۸ دفتر چک. دفتر روزانه برای پرسشهای عرضی است: چیزی که هیچ گزارشِ تکموضوعی جوابش را نمیدهد.
و اگر پرسشت «چه کسی این را عوض کرد» است، اینجا جوابش نیست. دفتر روزانه بازه را روی تاریخِ سند میبندد، پس ویرایشی که امروز روی سندِ پارسال انجام شده در دفترِ امروز دیده نمیشود و حذفشدهها اصلاً دیده نمیشوند. برای آن، §۴۳ تاریخچه کارها.
#پیوند با بخشهای دیگر
| موضوع | کجا |
|---|---|
| جهتِ ردیف و ستون تشخیص | §۴ |
| کد شرح و بابت | §۵ |
| سود فروشنده و ارزش افزوده | §۷ |
| گردش موجودی یک قلم | §۲۷ |
| دفتر چک | §۲۸ |
| حواله و کارتخوان | §۹ |
| چه کسی چه چیزی را عوض کرد | §۴۳ |
#۴۳. تاریخچه کارها: چه کسی، کِی، چه چیزی را عوض کرد
صفحهٔ «تاریخچه کارها» در منوی کناری، زیر گروهِ «سایر». نیاز به دسترسی history دارد.
#مسئلهای که این گزارش حل میکند
یک عصر، ماندهای که باید بخوانَد نمیخوانَد. دفتر روزانه را باز میکنی، همهچیز سرِ جایش است. تراز درست است. ولی عدد فرق دارد.
دلیلش تقریباً همیشه یکی از این سه چیز است: کسی سندِ قدیمی را دست زده، کسی ردیفی را پاک کرده، یا کسی عددی را عوض کرده. هیچکدامشان در گزارشهای معمولی دیده نمیشوند، چون گزارشهای معمولی وضعیتِ الان را نشان میدهند، نه راهی که به الان رسیده.
تاریخچه کارها همان راه را نشان میدهد:
امروز ساعت ۱۰:۰۸:۴۵ کاربر «یحیی» یک ردیف را حذف کرد. ردیف این بود: فروش النگو، ۱۵٫۰۳ گرم، عیار ۷۵۰، به خانم علمداری.
#ریز اتفاقات همان سند — v102
وقتی اختلاف مربوط به یک فاکتور مشخص است، لازم نیست ابتدا صفحهٔ کامل تاریخچه را فیلتر کنی. سند ذخیرهشده را باز کن و بالای آن ریز اتفاقات را بزن؛ همین دکمه در مرکز چاپ فاکتور نیز وجود دارد.
پنجرهٔ سندمحور این موارد را کنار هم میگذارد:
- زمان صدور، اولین چاپ و آخرین اتفاق با دقت ثانیه؛
- همهٔ ثبتها، ویرایشها، حذفها و چاپها به ترتیب وقوع؛
- نام کاربر، بخش تغییرکرده و مقدار قبلی و جدید؛
- نشان قرمز پس از چاپ برای هر ثبت، ویرایش یا حذفی که بعد از اولین چاپ رخ داده؛
- شمار رویدادهای چاپ و تغییرهای مشکوک پس از چاپ؛
- خروجی CSV فقط برای همان سند.
چرا اولین چاپ نقطهٔ مرجع است؟ نسخهای که به مشتری داده شده وضعیت سند در لحظهٔ چاپ است. اگر بعد از آن وزن، فی، شرح یا یک ردیف تغییر کند، حساب فعلی ممکن است با کاغذ مشتری فرق کند. این الزاماً به معنی تخلف نیست؛ فقط سریعترین سرنخ برای بررسی اختلاف است.
#بازهٔ پیشنهادی دوربین فروشگاه
ریز اتفاقات یک بازهٔ چهاردقیقهای آماده میکند: دو دقیقه قبل و دو دقیقه بعد از اولین تغییر مشکوک پس از چاپ. اگر تغییری پس از چاپ نباشد، بازه دورِ زمان چاپ قرار میگیرد. دکمهٔ «کپی بازه دوربین» متن آمادهای شامل شمارهٔ سند و ابتدا و انتهای بازه میدهد تا به مسئول بررسی دوربین تحویل بدهی.
نرمافزار خودش تصویر دوربین را نمیخواند و دربارهٔ کاربر قضاوت نمیکند. فقط زمان دقیق را از تاریخچهٔ مالی استخراج میکند تا بهجای مرور چند ساعت فیلم، همان چند دقیقه بررسی شود. اگر رویدادی برای سند قدیمی ثبت نشده باشد، صادقانه «بدون رویداد» نمایش داده میشود و زمان ساختگی تولید نمیشود.
#تفاوتش با دفتر روزانه — مهمترین نکتهٔ این صفحه
این دو گزارش شبیه به نظر میرسند و کاملاً متفاوتاند:
| دفتر روزانه | تاریخچه کارها | |
|---|---|---|
| بازه روی چه چیزی است | تاریخِ سند | زمانِ انجامِ کار |
| واحدِ هر سطر | یک ردیفِ سند | یک تغییر |
| چه چیزی را میبیند | سندهایی که هستند | کارهایی که شده — از جمله روی چیزی که دیگر نیست |
| حذفشدهها | دیده نمیشوند | با عکسِ کامل دیده میشوند |
مثالِ گویا: امروز سندِ پارسال را ویرایش میکنی. در دفتر روزانه (فقط امروز) هیچ اثری ندارد، چون تاریخِ آن سند پارسال است. در تاریخچه کارها همین امروز، بالای فهرست است.
عکسش هم درست است: سندی که امروز تاریخ خورده ولی هفتهٔ پیش ثبت شده، در دفتر روزانهٔ امروز هست و در تاریخچهٔ امروز نیست.
#ستونهای جدول
| ستون | چه میگوید |
|---|---|
| ☰ | شمارهٔ سطرِ گزارش |
| تاریخ | روزِ انجامِ کار — «امروز» و «دیروز» با همین کلمه نوشته میشوند |
| ساعت | تا ثانیه. وقتی دو نفر همزمان کار میکنند، دقیقه کافی نیست |
| کاربر | چه کسی این کار را کرد |
| رویداد | ثبت · ویرایش · حذف · چاپ · اقدام — و برای ویرایش، نامِ همان فیلد: «ویرایش وزن»، «ویرایش فی» |
| تراکنش | چه چیزی دست خورد: سند، ردیف، شخص، چک، حساب، کالا، وام، قسط، ذوب، مخارج، انبار، کاربر، سیستم |
| ID | کدِ سند یا کدِ همان مورد — با دابلکلیک بازش میکنی |
| شرح | متنِ خواندنیِ کار: «خانم علمداری — فروش النگو» |
| مقدار قبلی | عددی که بود (زمینهٔ قرمز) — روی حذف، دکمهٔ مشاهده |
| مقدار جدید | عددی که شد (زمینهٔ آبی) |
سطرهای هر روز زیرِ یک نوارِ جداکنندهٔ چسبان («امروز · ۱۴۰۵/۰۵/۲۱») گروه میشوند و لبهٔ رنگیِ سمتِ راستِ هر سطر رویداد را از دور معلوم میکند: سبز ثبت، کهربایی ویرایش، قرمز حذف.
#هر تغییر یک سطر است، نه هر ذخیره
اگر در یک ذخیره سه چیز عوض شده باشد، سه سطر میبینی. «ویرایش سند» بهتنهایی به درد نمیخورد؛ سؤالِ واقعی این است که کدام عدد از چه به چه رفت.
سندی که وزنِ یک ردیفش از ۲۰ به ۲۲ رفته و فیاش عوض شده، اینطور ثبت میشود:
| ساعت | رویداد | شرح | مقدار قبلی | مقدار جدید |
|---|---|---|---|---|
| ۱۰:۱۲:۰۳ | ویرایش وزن | خانم علمداری — سرویس رز | ۲۰٫۰۰۰ گ | ۲۲٫۰۰۰ گ |
| ۱۰:۱۲:۰۳ | ویرایش مبلغ | خانم علمداری — سرویس رز | ۳۰۱٬۷۸۰٬۰۰۰ | ۳۳۱٬۹۵۸٬۰۰۰ |
مبلغ هم ثبت میشود، با اینکه کاربر آن را تایپ نکرده. مبلغ از وزن و فی و اجرت درمیآید؛ ولی آن چیزی که در تراز جابهجا شده همین است. پس علاوه بر خانههایی که دست خورده، خانههای محاسباتی هم دیده میشوند: مبلغ، وزن ۷۵۰، درصد اجرت، اجرت عددی، سنگ.
#حذف: تنها جایی که عکس میگیریم
وقتی ردیفی حذف میشود، دیگر هیچجای سیستم وجود ندارد. پس در لحظهٔ حذف یک عکسِ کامل از آن گرفته و همانجا نگه داشته میشود. دکمهٔ مشاهده در ستونِ «مقدار قبلی» بازش میکند:
کد سند · تاریخ سند · نوع سند · طرف حساب · نوع ردیف · تشخیص · شرح · وزن · عیار · تعداد · فی · اجرت · سنگ · وزن ۷۵۰ · مبلغ
پایینِ پنجره نوشته میشود چه کسی و دقیقاً چه ساعتی پاکش کرده. همین برای شخصِ حذفشده، کاربرِ حذفشده و قبضِ ذوبِ حذفشده هم انجام میشود.
#حذفِ ردیفِ وسط، «سه ویرایش» نیست
سندی سه ردیف دارد و ردیفِ وسط را پاک میکنی. برنامهای که ردیفها را با شمارهٔ ترتیبی مقایسه کند، خبر میدهد: «ردیف ۲ عوض شد، ردیف ۳ عوض شد، ردیف ۳ حذف شد» — سه دروغ.
اینجا ردیفها با محتوایشان جفت میشوند نه با جایشان. اول ردیفهایی که موبهمو یکیاند، بعد ردیفهایی که همان کالایند و فقط عددشان عوض شده، بعد ردیفهایی که عددشان یکی است و شرحشان عوض شده. نتیجه:
- حذفِ ردیفِ وسط → دقیقاً یک سطرِ «حذف»، صفر ویرایشِ دروغین.
- جابهجا کردنِ ترتیبِ ردیفها → هیچ سطری. ترتیب، تغییرِ حساب نیست.
- حذفِ یکی و ویرایشِ دیگری در همان ذخیره → یک «حذف» برای همان ردیفِ درست، و ویرایش برای همان ردیفِ درست.
#بازه، فیلتر و جستوجو
بالای صفحه همان هشت بازهٔ آشنای دفتر روزانه است (فقط امروز · از دیروز · هفته · ماه · ۶ ماه · اول برج · ابتدای دوره · دستی) — با این تفاوت که روی زمانِ انجامِ کار اعمال میشود. پیشفرض فقط امروز است، پس صفحه که باز میشود کارِ امروز جلوی چشم است.
- خانهٔ ID — کدِ سند را میزنی و فقط کارهای همان سند میماند. برای «این فاکتور از اول چه بلایی سرش آمده» بهترین راه است.
- «هر چی هست» / «به انتخاب خودم» — حالتِ دوم سه کارتِ فیلتر باز میکند: رویداد، تراکنش، کاربر. کارتِ خالی یعنی «همه»، پس کارتها با هم جمع میشوند نه اینکه هم را خنثی کنند.
- جستوجو روی همهٔ ستونها است — کاربر، شرح، رویداد، و حتی مقدارِ قبلی و جدید. با همان جستجوی هوشمندِ بقیهٔ برنامه، پس غلط املایی و چیدمانِ انگلیسیِ کیبورد اشکالی ندارد.
- کلید H هر جای صفحه، مستقیم به جعبهٔ جستوجو میبَرَد.
- جدیدترین بالا پیشفرض روشن است؛ خاموشش کنی، ترتیبِ وقوع میشود.
- Enter یا دابلکلیک روی سطر، همان سندی را که کار رویش انجام شده باز میکند.
- خروجی CSV کلِ همین فهرستِ فیلترشده را میدهد، آمادهٔ باز شدن در اکسلِ فارسی.
چهار کارتِ آمار بالای جدول: کارِ این بازه · ثبت تازه · ویرایش · حذف.
#چه چیزهایی ثبت میشوند
ثبت و ویرایش و حذفِ سند و ردیف · شخص · کاربر · قبض ذوب · چک · وام و قسط · مخارج · اصلاح موجودی · پشتیبانگیری · ورود و خروج کاربر — و چاپِ فاکتور. چاپ عمداً ثبت میشود: بارها پیش میآید که فاکتوری در دستِ مشتری است و کسی نمیداند چه کسی و کِی درش آورده.
#چند نکتهٔ صادقانه
- تاریخچه از لحظهٔ نصبِ این نسخه شروع میشود. کارهای قبل از آن، اگر در لاگِ سادهی قدیمیِ اتاق فرمان بودهاند، اینجا هم دیده میشوند — ولی «مقدار قبلی / جدید» ندارند، چون آن موقع ثبت نمیشد.
- سقفِ نگهداری ۴۰۰۰ رویدادِ آخر است. از آن قدیمیتر خودکار میریزد تا حجمِ دفتر بیمهار بالا نرود.
- دکمهٔ «پاک کردن لاگ» در اتاق فرمان، تاریخچه کارها را هم پاک میکند. پیامِ تأییدش همین را میگوید.
- ویرایشِ سندی که هنوز ذخیره نشده ثبت نمیشود. معیار، لحظهٔ ذخیره است — چون تا ذخیره نشده، هنوز کاری انجام نشده.
#پیوند با بخشهای دیگر
| موضوع | کجا |
|---|---|
| گزارشِ کارِ امروز بر اساس تاریخ سند | §۴۲ |
| کاربران، دسترسیها و لاگِ ساده | §۱۳ |
| نسخهٔ پشتیبان | §۲۱ |
| جستجوی هوشمند | §۴۰ |
#۴۴. اجاره طلا: طلای سرمایهگذار نزد شما
صفحهٔ «اجاره طلا» در منوی کناری، کنارِ «وام و تسهیلات». نیاز به دسترسی lease دارد.
#قصه چیست
کسی — آشنا، همکار، سرمایهگذار — ۹۹۵ گرم آبشدهٔ ۷۵۰ میآورد و میگذارد دستِ شما. طلا مالِ اوست، ولی در مغازهٔ شما میچرخد: میفروشیدش، تبدیلش میکنید، سرمایهٔ در گردشتان میشود. در عوض، سرِ هر برج ۱٪ آن وزن را بابتِ اجاره به او میدهید.
دو قاعده دارد که با هم کلِ ماجرا هستند:
- اصل تکان نمیخورَد. طلبِ او همیشه همان ۹۹۵ گرم است — ماهِ اول، ماهِ دوازدهم، فرقی ندارد.
- اجاره هزینه است، نه بازپرداختِ اصل. آن ۹٫۹۵۰ گرم از جیبِ سودِ شما میرود، نه از حسابِ او.
#تلهٔ کهنه — و چرا این صفحه ساخته شد
راهِ بهظاهر بدیهی این است: یک سندِ پرداخت بزنی و ۱۰٫۰۸۴ گرم متفرقهٔ عیار ۷۴۰ (معادلِ همان ۹٫۹۵۰ گرمِ ۷۵۰) به او بدهی.
نتیجهاش این است:
| طلبِ سرمایهگذار | |
|---|---|
| قبل از پرداخت | ۹۹۵٫۰۰۰ |
| بعد از پرداخت | ۹۸۵٫۰۵۰ ❌ |
یعنی اجاره از اصل کم شد. عملاً سرمایهگذار اجارهٔ خودش را از جیبِ خودش داده. ماهِ بعد ۱٪ روی ۹۸۵ حساب میشود، ماهِ بعدترش روی کمتر… و بعد از یک سال هم اصل آب رفته و هم مغازه هیچ هزینهای در سود و زیانش ثبت نکرده. این خطا ماهها دیده نمیشود.
#راهِ درست: اول بستانکار، بعد پرداخت
هر دورهٔ اجاره دو لِنگ دارد و ترتیبش مهم است:
| لِنگ | چه میکند | اثرش بر موجودی |
|---|---|---|
| ۱. اضافه (کد ۹) | سرمایهگذار را به اندازهٔ ۹٫۹۵۰ گرم بستانکار میکند | هیچ — چیزی وارد مغازه نشده |
| ۲. پرداخت | همان اندازه به او میدهد (طلا یا پول) | خروجِ واقعی |
جمعِ دو لِنگ صفر است، پس ماندهاش همان ۹۹۵ میمانَد — ولی حالا در سود و زیان یک زیانِ ۹٫۹۵۰ گرمی ثبت شده که واقعیت است: هزینهٔ اجارهٔ سرمایهٔ در گردش.
ردیفِ «اضافه» تنها ردیفی است که وزن جابهجا میکند بیآنکه جنسی جابهجا شود. برای همین عمداً از کاردکس، پنلِ ورود ـ خروج و کارکردِ معاملات کنار گذاشته شده و فقط در سود و زیان دیده میشود. اگر وارد کارکرد میشد، چون فی ندارد بهعنوانِ جنسِ مجانی حساب میشد و یک سودِ ساختگی بهاندازهٔ نرخِ روز میساخت.
#ثبت قرارداد
دکمهٔ + قرارداد اجارهٔ طلا:
| خانه | توضیح |
|---|---|
| نامِ سرمایهگذار | فقط هنگام ثبت قابل تغییر است |
| وزنِ اصل و عیار | اگر آبشدهٔ ۷۵۰ است همان؛ اگر عیارِ دیگری است، خودش به گرمِ ۷۵۰ تبدیل میشود |
| اجارهٔ ماهانه (٪) | پیشفرض ۱ |
| تاریخ شروع | مبنای شمارشِ سررسیدها |
| مدت (ماه) | فقط برای نوارِ پیشرفت؛ اجباری نیست |
پیشنمایشِ زیر فرم، همان لحظه اجارهٔ هر ماه را نشان میدهد و معادلش را به متفرقهٔ ۷۴۰ — دقیقاً همان چیزی که با ماشینحساب میگیرید.
زیرحسابِ جدا. برای هر قرارداد یک حسابِ تازه به نامِ «فلانی — اجاره طلا» ساخته میشود. اگر همان شخص با شما داد و ستدِ عادی هم دارد، حسابش قاطی نمیشود؛ وگرنه یک ماه بعد نمیفهمید این ۹۹۵ گرم اصلِ سرمایه است یا طلبِ معامله.
اصلِ سرمایه را خودتان بزنید. قرارداد که ثبت شد، طلای تحویلی را با یک سندِ دریافت روی همان زیرحساب ثبت کنید (آبشده، کد ۱). اگر سرمایهگذار بهجای طلا حوالهٔ ریالی داده، همانطور که در ویدئوی مرجع هست، حواله را به طلا تبدیل و وزنِ حاصل — مثلاً ۴۸۴٫۹۱۰ گرم — را ثبت کنید.
#ثبت اجارهٔ هر دوره
دکمهٔ ثبت اجارهٔ دوره روی کارتِ قرارداد. وزنِ اجاره از قبل پر است و تاریخ روی سررسیدِ بعدی مینشیند. سه راهِ تسویه دارید:
| روش | چه سندی ساخته میشود |
|---|---|
| طلا — متفرقه یا آبشده | یک سندِ «سایر» با دو ردیف: اضافه (ورود) + جنسِ پرداختی (خروج). عیارِ پرداختی را میدهید، وزنِ فیزیکی خودش حساب میشود |
| پول — نقدی یا حواله | یک سندِ «سایر» (اضافه + پولی کردنِ اجاره) که طلبِ او را ریالی میکند، بهعلاوهٔ یک سندِ «پرداخت» جدا که پول را از صندوق یا حسابِ بانکیِ انتخابی بیرون میبرد |
| فعلاً فقط بستانکارش کن | فقط ردیفِ اضافه. اجاره روی حسابش میمانَد تا بعداً بدهید |
چرا پرداختِ پولی دو سند است؟ چون در این برنامه صندوق و حسابِ بانکی فقط از سندهای دریافت و پرداخت تغذیه میشوند. اگر ردیفِ پرداخت داخلِ همان سندِ «سایر» میماند، طلبِ سرمایهگذار صفر میشد ولی پول از هیچ صندوقی کم نمیشد.
#کارتِ هر قرارداد
- اصل، اجارهٔ هر دوره، دورههای پرداختشده و سررسیدِ بعدی روی کارت است.
- برچسبِ سبز «بهروز» یا قرمز «n دوره سررسید شده» — بر اساس فاصلهٔ تاریخِ شروع تا امروز به ماهِ جلالی.
- دفترِ قرارداد: تمام سندهای همین قرارداد، دوره به دوره، با ستونِ اجاره و ستونِ پرداخت.
- حساب اجاره: کارتِ همان زیرحساب با گردشِ کامل.
- حذفِ قرارداد، سندهای اجارهاش را هم میبَرَد؛ ولی زیرحسابِ شخص و سندِ اصلِ سرمایه دستنخورده میمانَد.
#نگهبانِ اصل — کارتِ قرمز
پس از هر بار محاسبه، ماندهای که باید باشد با ماندهای که هست مقایسه میشود:
ماندهٔ مورد انتظار = اصل + اجارهٔ ثبتشده − اجارهٔ تسویهشده
اگر این دو نخوانند، کارتِ قرارداد قرمز میشود و بالای صفحه هم هشدار میآید: «اصل جابهجا شده» با همان دو عدد و اختلافشان. تقریباً همیشه یعنی یک سندِ دستی اجاره را مستقیم از طلبِ سرمایهگذار کم کرده — همان تلهٔ بالا.
آستانهٔ این هشدار با تعدادِ دورهها کمی بزرگ میشود. علتش صادقانه است: وقتی ۹٫۹۵۰ گرمِ ۷۵۰ با متفرقهٔ ۷۴۰ پرداخت میشود، عددِ فیزیکی ۱۰٫۰۸۴ گرم است و برگشتش ۹٫۹۴۹ میشود نه دقیقاً ۹٫۹۵۰. این نیمسوتها ذاتِ تبدیلِ عیارند، نه خطا؛ اشتباهِ واقعی صدها برابرِ این است و همچنان گیر میافتد.
#در سود و زیان کجاست
در بخشِ اقلامِ دیگر یک سطرِ تازه نشسته: «اضافه و اجارهٔ طلا» — جمعِ همهٔ ردیفهای کد ۹، هم به گرم و هم به ریالِ نرخِ روز، همیشه با علامتِ زیان. کنارِ سطرِ قدیمیِ «تخفیفهای دادهشده» مینشیند؛ آن یکی کسرِ ریالی است و این یکی اضافهٔ وزنی.
#نامِ قرارداد را کلی بگذارید
در ویدئوی مرجع نکتهای هست که ارزشِ تکرار دارد: زیرحساب را «اجاره طلای مهرماه» نگذارید. اسمِ کلی بگذارید — «اجاره طلا» — تا سالهای بعد هم همین حساب ادامه پیدا کند و مجبور نشوید هر ماه حسابِ تازه بسازید. بابتِ ردیفها هم به همین دلیل ثابت است: «اجاره طلا»، نه «اجارهٔ اسفند».
#اجاره در تصویر کاملِ مخارج
تا اینجا اجارهٔ طلا فقط در سود و زیان دیده میشد. ولی وقتی آخرِ برج میخواهید بپرسید «این ماه چقدر خرج کردم؟»، جواب یکجا نبود: اجارهٔ مغازه و قبضِ برق در «مخارج» بودند و اجارهٔ طلا جای دیگر.
حالا در صفحهٔ مخارج مغازه اجارهٔ هر دوره کنارِ بقیهٔ مخارج مینشیند:
- سطرش با نوارِ طلایی و برچسبِ «طلایی» مشخص است و مبلغش به گرم نوشته میشود، با معادلِ ریالیِ نرخِ روز زیرش.
- بالای فهرست، کارتِ «تصویر کاملِ مخارج»: مخارجِ ریالی + اجارهٔ طلا = جمعِ هزینهٔ برج.
- این سطر خواندنی است؛ از خودِ قرارداد ساخته میشود و از همانجا هم عوض میشود.
- اگر این نمایش را نمیخواهید، در فرمِ قرارداد تیکِ «اجاره در فهرستِ مخارج هم دیده شود» را بردارید.
مهم — دوبار حساب نمیشود. اجارهٔ طلا همان یک بار در «سود و زیان» ذیلِ «اضافه و اجارهٔ طلا» بهعنوان زیانِ طلا ثبت شده است. برای همین در جمعِ مخارج عملیاتی نمیآید و فقط در کارتِ «تصویر کامل» کنارش گذاشته میشود. اگر در جمعِ ریالی هم مینشست، سودِ شما دوبار کم میشد.
اجارهٔ طلا وزنی است نه ریالی. معادلِ ریالیاش با نرخِ امروز حساب میشود، پس با بالا و پایین شدنِ مظنه عوض میشود — و این درست است: هزینهٔ واقعیِ شما همان وزن است.
#پیوند با بخشهای دیگر
| موضوع | کجا |
|---|---|
| کدهای شرح و کد ۹ «اضافه» | §۵ |
| ستون تشخیص (ورود / خروج) | §۴ |
| سود و زیان و اقلامِ دیگر | §۱۲ |
| وام بانکی (که برعکسِ این است) | §۲۲ |
| حساب بانکی و صندوق | §۸ |
#۴۵. کارکرد ارز و سکه (سایت فروشگاه)
این بخش در سایت فروشگاه است، نه پنل ادمین: سربرگ «کارکرد ارز و سکه». نیاز به دسترسی reports دارد.
#این گزارش چه میگوید
سودِ این صفحه تحققیافته نیست — نسبت به قیمت روز سنجیده میشود. یعنی: «اگر همین حالا مغازه را ببندی، چقدر جلو یا عقبی؟»
| سمت | فرمول |
|---|---|
| خرید | (قیمت روز − میانگین فی خرید) × تعداد — هرچه ارزانتر خریده باشی، سود بیشتر |
| فروش | (میانگین فی فروش − قیمت روز) × تعداد — هرچه گرانتر فروخته باشی، سود بیشتر |
«میانگین فی» میانگینِ وزنیِ تعداد است، نه میانگین ساده. معاملهها بر اساس (نوع معامله × دارایی) گروه میشوند، پس دو خریدِ امامی در یک بازه یک ردیف میشوند.
#دفترچهٔ قیمت روز
مبنای همهٔ محاسبههای این صفحه است و دستی وارد و ذخیره میشود. کاتالوگ ثابت دارد:
- سکه: تمام بهار آزادی، امامی، طرح قدیم، نیم، ربع، سکه گرمی
- ارز: دلار، یورو، درهم، لیر، پوند
- گرم ۷۵۰ — برای تبدیل سود ریالی به معادل گرم
اگر نرخ آنلاین گرم ۷۵۰ در دسترس باشد، یک دکمهٔ «آنلاین» بالای دفترچه میآید که با یک کلیک همان نرخ را میگذارد.
داراییای که قیمت روزش خالی است ارزشگذاری نمیشود. بهجای اینکه صفر حساب شود و عددِ نهایی را خراب کند، اسمش در یک هشدار جداگانه بالای جدول میآید. این همان اصلِ «صداقت در نبودِ داده» است.
#بازهٔ زمانی و تفکیک سهم
بازهها: امروز · یک هفته · یک ماه · از ابتدای دوره · بازهٔ دلخواه.
بالای جدول یک زنجیره میبینی:
تا پیش از بازه + سهم این بازه = تجمعی تا پایان بازه
این سه عدد همیشه با هم جور درمیآیند؛ هیچ سودی دوبار شمرده یا گم نمیشود. پس میتوانی مطمئن باشی که «سود این هفته» واقعاً سهمِ همین هفته است، نه تکرارِ سودِ قبلی.
#جدول ریز کارکرد
ستونها: نوع (خرید/فروش) · دارایی · تعداد · میانگین فی · قیمت روز · اختلاف هر واحد · سود/زیان.
فروشها بالا میآیند و بعد بر اساس بزرگیِ اثر مالی مرتب میشوند. روی مبلغ سود بزن تا زنجیرهٔ محاسبه باز شود و قدمبهقدم ببینی این عدد از کجا آمده.
#شاخصهای بالای صفحه
سود/زیان این بازه (تومان) · معادل طلای ۷۵۰ (گرم) · ارزش موجودی باز به قیمت روز · تعداد اسناد ارز و سکه در بازه.
#موجودی باز
مانده پس از کسر فروش از خرید، به قیمت روز. یعنی از هر دارایی چقدر دستت مانده و امروز چقدر میارزد.
#۴۶. کار جور: سی قلم خردهریز در یک ردیف
بنکدار که جنس میآورد، فاکتورش سیچهل ردیف میشود: «انگشتر کارتیر فیوژن»، «نیمست آلبرناردو»، «کارتیر سیاهقلم»… هر کدام چند گرم. اجرتِ همهشان هم به هم نزدیک است — چهار درصد، چهار درصد، سه درصد.
اینها عملاً یک جنساند: خردهریزِ فانتزی. اگر یکییکی در انبار بمانند، هر بار که بخواهی بفروشی باید سی ردیف بزنی و فاکتورت هم خوانا نیست. کارِ درست این است که یک بار همه را زیرِ یک نام جمع کنی: «کار جور فانتزی».
پنل این کار را در دو جا انجام میدهد؛ کدامش را لازم داری بستگی دارد به اینکه کجا ایستادهای.
#الف) در انبار: سی قلم را برای همیشه یکی کن
این کارِ «یکبار»ی است. از حالا آن سی قلم دیگر جدا وجود ندارند و همهشان به نامِ کار جور در انبارند.
۱. برو به موجودی ← اجناس. ۲. قلمهایی را که میخواهی جمع کنی تیک بزن (همان تیکِ کنارِ هر ردیف که برای اصلاح موجودی هم استفاده میکنی). ۳. از نوارِ بالای جدول بزن «ادغام در کار جور». ۴. نامِ قلمِ تازه را بنویس — مثلاً «کار جور فانتزی». اگر قبلاً چنین نامی تعریف کردهای، از فهرستِ پیشنهادی انتخابش کن. ۵. کارتِ وسطِ فرم نشانت میدهد قلمِ تازه چه شکلی میشود: وزن، عیارِ میانگین، اجرتِ میانگین، فیِ دریافتی. ۶. پایینِ فرم یک نوارِ سبز است: ماندهٔ سند: ۰٫۰۰۰ گ۷۵۰. تا این نوار سبز نشده، دکمهٔ ادغام کاری نمیکند.
بزن «ادغام کن». یک سندِ اصلاح موجودی ساخته میشود که در آن هر سه قلمِ قدیمی «خروج» خوردهاند و کار جور «ورود». اشتباه شد؟ از «اصلاحهای اخیرِ موجودی» همان سند را لغو کن؛ همهچیز دقیقاً برمیگردد.
#مثال واقعی
| قلم | وزن | عیار | اجرت | وزن ۷۵۰ |
|---|---|---|---|---|
| انگشتر کارتیر فیوژن | ۹۷٫۵۵ | ۷۵۰ | ۴٪ | ۱۰۱٫۴۵ |
| نیمست آلبرناردو | ۳۶۸٫۸۸ | ۷۵۰ | ۴٪ | ۳۸۳٫۶۴ |
| کارتیر سیاهقلم | ۵۷٫۳۶ | ۷۵۰ | ۳٪ | ۵۹٫۰۸ |
| کار جور فانتزی | ۵۲۳٫۷۹ | ۷۵۰ | ۳٫۸۹۰۴۹٪ | ۵۴۴٫۱۷ |
وزنها جمع شدهاند و وزنِ ۷۵۰ هم. اجرتِ ۳٫۸۹۰۴۹٪ عددی است که پنل خودش پیدا میکند: همان درصدی که وزنِ ۷۵۰ِ قلمِ تازه دقیقاً برابرِ جمعِ سه قلمِ قبلی بشود. نه چیزی ساخته شد، نه چیزی سوخت.
چرا این عدد را خودت با ماشینحساب حساب نمیکنی؟ چون میانگینِ سادهٔ درصدها جوابِ درست نمیدهد وقتی عیارها یکی نباشند. مثال: ۱۰۰ گرمِ عیار ۷۵۰ با اجرت ۱۰٪ و ۵۰ گرمِ عیار ۹۰۰ بدون اجرت. میانگینِ درصدها ۶٫۶۷٪ درمیآید، ولی جوابِ درست ۶٫۲۵٪ است — و آن ۰٫۴۲ درصدِ اختلاف روی این وزن یعنی دوسومِ گرم طلا که از هوا آمده. پنل حسابِ درست را میکند.
#فیِ دریافتی هم میانگین میگیرد
اگر قلمها فیِ دریافتی داشته باشند (یعنی میدانی هر گرم را چند خریدهای)، فیِ کار جور میانگینِ وزنی میشود، نه میانگینِ ساده:
| قلم | وزن | فی دریافتی | مبلغ |
|---|---|---|---|
| دستبند لوکس آنجلا | ۹۲٫۱۰ | ۱٬۴۰۰٬۰۰۰ | ۱۲۸٬۹۴۰٬۰۰۰ |
| سرویس رز | ۹۹٫۱۸ | ۱٬۶۰۰٬۰۰۰ | ۱۵۸٬۶۸۸٬۰۰۰ |
| کارتیر H | ۸۸٫۷۴ | ۱٬۵۰۰٬۰۰۰ | ۱۳۳٬۱۱۰٬۰۰۰ |
| جمع | ۲۸۰٫۰۲ | ۱٬۵۰۲٬۵۲۸ | ۴۲۰٬۷۳۸٬۰۰۰ |
میانگینِ سادهٔ سه فی ۱٬۵۰۰٬۰۰۰ میشود؛ جوابِ درست ۱٬۵۰۲٬۵۲۸ است. اختلافش کم به نظر میآید ولی روی همین یک قلم ۷۰۸ هزار ریال است — و این عدد پایهٔ سودِ فردای توست، پس باید درست باشد.
#ب) در فاکتور: سه ردیفِ یک سند را یکی کن
اینجا فرق دارد. چیزی در انبار جابهجا نمیشود؛ فقط فاکتورِ مشتری خواناتر میشود.
۱. در سند، ردیفها را با نگهداشتنِ <kbd>Ctrl</kbd> و کلیک انتخاب کن (یا <kbd>Shift</kbd> برای یک بازه) — همان انتخابی که در بخش ۲۵ توضیح داده شده. ۲. در نوارِ سرمهایِ پایین صفحه بزن «کار جور». ۳. نام بگذار و اجرتِ پرداختی به مشتری را بنویس.
پایینِ فرم یک نوار است که میگوید اثر روی مبلغِ سند چقدر است:
- اگر نرخ را دست نزنی، نوار سبز است و میگوید «بدون تغییر» — ادغام هیچ پولی جابهجا نکرد.
- اگر نرخِ بالاتری بگذاری، نوار آبی میشود و عددِ سود را نشان میدهد.
- اگر پایینتر بگذاری، قرمز میشود و میگوید این تفاوت از جیبِ توست.
مثال: همان سه ردیفِ بالا با فیِ ۱٬۵۰۰٬۰۰۰ جمعاً ۸۱۶٬۲۵۲٬۰۰۰ ریال میشوند. نرخِ خنثی ۳٫۸۹٪ است. اگر تصمیم بگیری همه را ۶ درصد به مشتری بدهی، نوار میگوید +۱۶٬۵۷۴٬۱۰۰ ریال سود. این تصمیمِ توست، نه اشتباهِ برنامه — ولی عددش را پیش از ثبت میبینی.
نگهبانِ صفرِ اضافه. اگر تفاوت از یکپنجمِ جمعِ قبلی بگذرد، یک هشدارِ قرمز پایینِ فرم میآید: «نکند یک رقم اضافه خورده باشد؟» چون تایپِ ۶۰ بهجای ۶ همان چیزی است که مانده را چند صد میلیون میپراند.
#ادغام برگشتپذیر است
ردیفِ ادغامشده یک دکمهٔ طلاییِ کوچک کنارش دارد. بزنش تا دقیقاً همان ردیفهای اصلی برگردند — با همان وزن، همان اجرت، همان شرح. هیچچیز بازسازی نمیشود؛ ردیفها روی خودِ ردیفِ ادغامشده نگه داشته شدهاند.
#چه چیزی ادغام نمیشود
پنل «نه» که میگوید، دلیلش را هم مینویسد:
| وضعیت | چرا |
|---|---|
| فقط یک قلم انتخاب شده | ادغام دستِکم دو تا میخواهد |
| نامِ مقصد موجودی دارد | ادغام روی موجودیِ موجود، آن را بیسند تجدید ارزش میکند. نامِ تازه بگذار |
| نامِ مقصد خودش در انتخاب است | یا از انتخاب برش دار، یا نامِ دیگری بگذار |
| ردیفِ نقد، سکه یا کالای غیرطلایی | فقط ردیفهای طلا ادغام میشوند |
| ردیفِ سنگدار | مبلغِ سنگ در درصدِ اجرت نمیگنجد |
| ردیفِ قسط، چک یا کارتخوان | اینها هر کدام سازوکارِ خودشان را دارند |
| تشخیصِ ردیفها یکی نیست | ورود و خروج در یک ردیف جا نمیشوند |
| فیِ ردیفها یکی نیست | یک ردیف بیشتر از یک فی ندارد |
#۴۷. آبشدهٔ شرطی: طلایی که هنوز عیارش را نمیدانی
همکار زنگ میزند: «ششصد گرم آبشده دارم، میخواهی؟» میگیری. وزنش را همانجا با ترازو میزنی — ۶۰۴٫۸۱ گرم. ولی عیارش را کسی نمیداند تا وقتی برگهٔ ریگیری بیاید، و آن ممکن است فردا بیاید یا هفتهٔ بعد.
معامله اما همین امروز افتاده. ماندهٔ آن همکار همین حالا باید یک عدد داشته باشد.
راهحل همین است: ردیف را با یک عیارِ موقت ثبت میکنی، و وقتی جواب آمد با یک حرکت درستش میکنی. به این ردیف میگوییم آبشدهٔ شرطی.
#ثبتِ ردیفِ شرطی
۱. سند را مثل همیشه باز کن (خرید، فروش، دریافت، پرداخت — فرقی نمیکند). ۲. ردیف را طلا بگذار و در ستونِ شرح، کدِ ۳ — آبشده شرطی را انتخاب کن. ۳. بلافاصله زیرِ ردیف یک نوارِ کهربایی باز میشود با سه کادر:
| کادر | چیست |
|---|---|
| ریگیری | نامِ آزمایشگاهی که آبشده را برای عیارسنجی بردهاید — مثلاً «فارس آنالیز» |
| شمارهٔ قبض | شمارهٔ روی برگهٔ همان آزمایشگاه |
| عیارِ موقت | عیاری که تا رسیدنِ جواب در حساب مینشیند (پیشفرضش از تنظیمات میآید) |
۴. وزن را بزن، فی را بزن، سند را ذخیره کن. تمام.
در ستونِ عیار یک نشانِ کهربایی میبینی: شرطی. یعنی «این عدد هنوز نهایی نیست».
ریگیری و شمارهٔ قبض را حتماً پر کن. این دو با هم شناسنامهٔ لُنگه هستند. اگر خالی بمانند، ردیف در دفتر شرطی زیرِ سطرِ «بیشناسنامه» مینشیند و وقتی جواب آمد، پنل نمیداند کدام سندها را باید با هم اصلاح کند. نوارِ زیرِ ردیف هم همانجا قرمز میشود و یادت میاندازد.
#یک لُنگه، چند نفر
اینجا نکتهٔ اصلی است. آن ۶۰۴٫۸۱ گرم معمولاً پیشِ خودت نمیماند:
| سند | طرف حساب | جهت | وزن |
|---|---|---|---|
| ۵۰۰۱ | گالری رضوی | دریافت | ۶۰۴٫۸۱ گ |
| ۵۰۰۲ | اکبری | پرداخت | ۲۵۴٫۴۹ گ |
| ۵۰۰۳ | برزگر | پرداخت | ۱۲۸٫۴۹ گ |
| ماندهٔ لُنگه | ۲۲۱٫۸۳ گ |
سه سند، سه طرف حساب — ولی یک قبضِ آزمایشگاه. وقتی جواب برسد، هر سه با هم باید عوض شوند.
برای همین در هر سه ردیف همان «فارس آنالیز / ۴۶۵۲۴۶۱» را مینویسی. از آن به بعد پنل خودش میداند این سه یکیاند: زیرِ ردیف مینویسد «۳ ردیف با همین قبض — یک جواب همه را با هم اصلاح میکند».
#دفتر شرطی
برو به ذوب و آبشده. بالای صفحه دو دکمه است: دفتر ذوب و دفتر شرطی. روی عددِ قرمزِ کنارِ «دفتر شرطی» تعدادِ لُنگههای منتظرِ جواب نوشته شده.
دفتر شرطی هر لُنگه را یک سطر نشان میدهد، نه هر ردیف را:
- دریافتی / پرداختی / ماندهٔ لُنگه — همان جمعی که بالا دستی زدیم.
- طرفحسابها — اسمِ همهٔ کسانی که تکهای از این لُنگه دستشان است.
- وضعیت — «۳ منتظرِ جواب» یا «قطعی».
روی سطر کلیک کن تا تکهها باز شوند: هر ردیف با سندش، تاریخش، جهتش و معادلِ ۷۵۰اش. دکمهٔ کنارِ هر ردیف همان سند را باز میکند.
بالای دفتر یک کادرِ جستوجو هست که همهچیز را با هم میگردد — نامِ ریگیری، شمارهٔ قبض، نامِ طرف حساب، شمارهٔ سند، حتی وزن. و چهار دکمهٔ بازه: باز / یک ماه / سه ماه / همه. پیشفرض روی «باز» است، چون آنچه هر روز لازم داری همان لُنگههایی است که هنوز جوابشان نیامده.
ماندهٔ منفی یعنی خطا. اگر بیشتر از آنچه گرفتهای پخش کرده باشی، ماندهٔ لُنگه قرمز میشود و زیرش مینویسد «بیش از دریافت پخش شده». یا وزنی اشتباه ثبت شده، یا ردیفِ دریافتش جا افتاده.
#ثبتِ جوابِ عیار
جوابِ آزمایشگاه رسید: عیار ۷۴۷.
از دفتر شرطی روی همان لُنگه دکمهٔ «ثبت جواب عیار» را بزن (همین دکمه زیرِ خودِ ردیفِ سند هم هست). عدد را بنویس. پیش از اینکه چیزی ثبت شود، پایینِ فرم میبینی دقیقاً چه اتفاقی میافتد:
| طرف حساب | ردیف | اثر بر مانده |
|---|---|---|
| گالری رضوی | ۱ | −۲٫۴۱۹ گ |
| اکبری | ۱ | +۱٫۰۱۸ گ |
| برزگر | ۱ | +۰٫۵۱۴ گ |
| ۳ ردیف در ۳ سند | خالص −۰٫۸۸۷ گ |
این جدول همان چیزی است که ویدئوی مرجع ندارد. آنجا فقط یک جملهٔ قرمز است و یک «مطمئنی؟» — و تو باید حدس بزنی چه شد.
بزن «ثبت جواب». هر سه سند با هم اصلاح میشوند، نشانِ کهربایی سبز میشود و مینویسد جواب ۷۴۷.
جوابِ عیار یک معامله نیست، یک تجدیدِ ارزیابی است. وزن دست نمیخورد، فی دست نمیخورد، مبلغِ ریالیِ سند دست نمیخورد. فقط عیار — و در نتیجه معادلِ ۷۵۰ — عوض میشود. اگر چیزِ دیگری تکان خورد، خبر بده؛ باگ است.
#اشتباه شد؟ لغو کن
پایینِ دفتر شرطی فهرستِ «ثبتهای اخیرِ جواب» است، و کنارِ هر کدام دکمهٔ لغو. بزنی، همان ردیفها دقیقاً به عیارِ موقتِ قبلیشان برمیگردند و دوباره «منتظرِ جواب» میشوند.
این مهم است چون یک صفرِ اضافه — ۷۴۷۰ بهجای ۷۴۷ — ماندهٔ چند نفر را با هم میپراند. البته پنل خودِ عددِ نامعقول را هم نمیپذیرد:
| ورودی | نتیجه |
|---|---|
| خالی یا صفر | رد |
| منفی | رد |
| بالاتر از ۱۰۰۰ | رد — «نکند یک رقم اضافه خورده؟» |
| پایینتر از ۶۵۰ | قبول، ولی با هشدارِ «مطمئنی؟» |
#عیارِ مبنای شرطی (تنظیمات)
در تنظیمات ← اطلاعات فروشگاه و نرخ کادری هست به نامِ «عیار مبنای آبشدهٔ شرطی». این همان عددی است که هر ردیفِ شرطیِ تازه با آن شروع میشود. کنارش هم نوشته چند لُنگه منتظرِ جواب است.
این تنظیم قفل ندارد و هر وقت بخواهی عوض میشود. دلیلش این است که عددِ مبنا لحظهٔ ثبت روی خودِ ردیف مهر میشود؛ از آن به بعد ردیف عددِ خودش را دارد. پس عوضکردنِ تنظیم فقط ردیفهای آینده را عوض میکند و هیچوقت ماندهٔ لُنگههای بازِ قبلی را عقبگرد بازنویسی نمیکند.
در نرمافزارهای دیگر این تنظیم تا وقتی حتی یک لُنگهٔ باز داری قفل است و باید «اول همه را تعیینتکلیف یا حذف کنی». در یک بنکداریِ واقعی که هیچوقت صفر لُنگهٔ باز ندارد، آن تنظیم عملاً هرگز قابلِ تغییر نیست. اینجا لازم نیست.
#چند نکتهٔ ریز
- عیارِ شرطی سودِ عیار نمیسازد. عیارِ موقت روی عیارِ فیزیکیِ ردیف مینشیند، نه روی ستونِ «عیار شخصی». اگر آنطور بود، حدسِ ۷۳۵ روی ۳۸۴٫۳۲ گرم، ۷٫۶۸۶ گرم «زیانِ عیار» جعل میکرد — زیانی که اصلاً اتفاق نیفتاده، چون عیار فقط نامعلوم است نه باخته.
- ستونِ عیار تا رسیدنِ جواب قفل است. عددش را «عیارِ موقت» در نوارِ زیرین میدهد؛ دو جا برای یک عدد یعنی دردسر.
- ردیفهای قدیمی هم دیده میشوند. هر ردیفی که شرحش کد ۳ باشد — حتی اگر پیش از این نسخه ثبت شده — در دفتر شرطی «باز» فرض میشود تا از قلم نیفتد.
- شرح را عوض کنی، پرچمها پاک میشوند. ردیفی که دیگر شرطی نیست، در دفتر نمیماند.
#۴۸. مرجوعی نزدِ سازنده و بنکدار: دفترِ فی و خرید خالص
بخش ۳۵ مرجوعیِ تکفروشی را گفت: مشتری فاکتورِ ریالی را پس میآورد و مبلغش با سود و مالیاتش برمیگردد. این بخش دربارهٔ همان کار در بنکداری است، جایی که حساب به وزن و درصد بسته میشود نه به ریال: جنس را از سازنده با «فیِ ٪۱۲» میگیری و به مغازهدار با «٪۱۵» میدهی.
اینجا مبلغی خراب نمیشود؛ چیزی که خراب میشود آمار است: میانگینِ فیِ دریافتیِ آن جنس، و خرید خالصِ ماه. و چون هیچ عددی روی سند غلط نمیشود، ماهها بعد لو میرود.
قاعدهٔ یکخطی: مرجوعی را با تشخیصِ مرجوعی بزن، نه با تشخیصِ عادیِ جهتِ مخالف.
#صحنهٔ ۱ — مغازهدار جنس را پس میآورد
چند روز پیش چند کار به این مشتری دادهای؛ امروز بخشی از یکی را پس میآورد.
اول: سندِ جدید بزن، در ادامهٔ همان فاکتورِ قبلی نه. دو دلیل دارد و هر دو عملی است:
- آن فاکتور چاپ شده و تحویلِ خودش شده. نسخهٔ کاغذیِ دستِ او با نسخهٔ داخلِ پنل یکی نمیماند.
- تاریخش قدیم است. مرجوعیِ امروز باید به تاریخِ امروز بنشیند، وگرنه در دفتر روزانه و کاردکس روزِ اشتباهی میافتد.
دوم: تشخیصِ ردیف را «دریافت مرجوعی» بگذار (کد ۵). بهمحضِ انتخاب، فهرستِ پیشنهادیِ جنسها با رنگِ متفاوت میآید و فقط همان اجناسی است که قبلاً به همین شخص پرداخت کردهای — نه کلِ کاتالوگ. جنسی که هرگز به او ندادهای، نمیتواند از او مرجوع شود.
| جنس | دستبند رولکس |
| وزنِ مرجوعی | ۲۴٫۸۰۰ |
| اجرتی که با آن داده بودی | ٪۱۵ |
| فیِ دریافتیِ خودت از سازنده | ٪۱۰ |
ماندهٔ سند شاملِ وزنِ اجرت هم میشود، نه فقط وزنِ خالی — همان درصدی که در دلِ کار است با خودِ جنس برمیگردد.
#اگر همین ردیف را با تشخیصِ «دریافت» بزنی
سه چیز خراب میشود و هیچکدام روی صفحهٔ سند دیده نمیشود:
| با «دریافت مرجوعی» ✅ | با «دریافت» عادی ❌ | |
|---|---|---|
| خودِ سند | میگوید این ردیف مرجوعی بوده | میگوید از این مشتری جنس خریدی |
| میانگین فیِ دریافتیِ دستبند | ٪۱۰ میماند | بالا میرود |
| خرید خالصِ ماه | دستنخورده | ۲۴٫۸۰۰ گرم اضافه میشود |
| ماندهٔ طرف حساب | درست | هم درست است — و همین فریبندهاش میکند |
سطرِ آخر مهمترین سطرِ این بخش است: ماندهٔ حساب در هر دو حالت یکی است. پس سند بهنظر سالم میآید و اشتباه فقط در گزارشها دیده میشود.
عددِ میانگین فی. فرض کن ۱۰۰ گرم دستبند رولکس با ٪۱۰ از سازنده گرفته باشی. اگر مرجوعیِ ۲۴٫۸۰۰ را با تشخیصِ «دریافت» و اجرتِ ٪۱۵ ثبت کنی:
(۱۰۰ × ۱۰ + ۲۴٫۸ × ۱۵) ÷ ۱۲۴٫۸ = ٪۱۰٫۹۹
یعنی از آن لحظه پنل فکر میکند این کار را ٪۱۰٫۹۹ خریدهای، در حالی که ٪۱۰ خریدهای. انگار همان جنس را از یک نفرِ دیگر گرانتر گرفته باشی. از آن به بعد سودِ هر فروشِ همان جنس کمتر از واقع دیده میشود.
در موجودی اجناس روی همان قلم دوبار کلیک کن؛ میگوید فیِ دریافتی ٪۱۰ بوده و بعد از کدام سند عوض شده. راهِ پیدا کردنِ رَدِ خرابی همین است.
راهِ اصلاح: سند را از قفل دربیاور، روی ردیف کلیک کن و Delete (یا حذف) بزن، بعد همان ردیف را با تشخیصِ مرجوعی ثبت کن. میانگین فی و خرید خالص هر دو سرِ جایشان برمیگردند.
#صحنهٔ ۲ — ما به سازنده جنس پس میدهیم
قرینهٔ صحنهٔ ۱، با یک پیچِ اضافه.
قبلاً چند کار از احسان حاجیصفی (کارگاه) گرفتهای. حالا بخشی از یکی را پس میدهی: سندِ جدید از نوعِ «دریافت»، با ردیفی که تشخیصش «پرداخت مرجوعی» است. پنل خودش برچسبِ ردیف را «پرداخت مرجوعی» میگذارد و فهرستِ پیشنهادی هم فقط اجناسی است که از همین شخص گرفتهای.
#راهِ سریعتر: «مرجوع شود»
اگر سندِ دریافتِ آن جنس دمِ دستت است:
۱. سند را از حالتِ قفل دربیاور. ۲. روی ردیفِ همان جنس کلیک کن. ۳. «مرجوع شود» را بزن — یا Ctrl + R. ۴. میپرسد «همین سند» یا «سند جدید». تاریخِ آن سند قدیم است، پس سند جدید.
ردیفِ مرجوعی با همان مشخصات و همان درصدِ سندِ اصلی ساخته میشود؛ فقط وزن را روی وزنی که واقعاً پس میدهی اصلاح کن.
| جنس | انگشتر مروارید |
| وزنِ مرجوعی | ۳۴٫۲۲۰ |
| فیِ دریافتیِ اصل | ٪۱۲ |
| درصدِ توافقیِ مرجوعی | ٪۶ |
#پیچِ ماجرا: سازنده با همان فی پس نمیگیرد
«ما دیگر ٪۱۲ از تو نمیگیریم، ٪۶ میگیریم؛ نصفِ زیانِ مرجوعی پای خودت.» این عرفِ بازار است، نه استثنا: کار ساخته شده، اجرتش خرج شده، و برگرداندنش برای سازنده هزینه دارد.
پس در گزارشِ کارکرد اجناس یک زیان میبینی و درست است:
۳۴٫۲۲۰ × (۶ − ۱۲) ÷ ۱۰۰ = زیانِ ۲٫۰۵۳۲ گرمِ ۷۵۰
روی همان ردیف دوبار کلیک کن؛ میگوید «فیِ دریافتی ٪۱۲ بوده، پرداخت مرجوعی با ٪۶ اتفاق افتاده». این زیان باید ثبت شود — ٪۶ اختلاف روی آن وزن واقعاً از سودِ تو کم شده. اگر گزارش این را نشان ندهد، سودِ ماهت شش درصدِ آن وزن بیشتر از واقعیت است.
#دفترِ فی: ٪۶ نباید جای ٪۱۲ را بگیرد
پنل برای هر شخص، هر جنس و هر نوع سند آخرین فی و آخرین درصدِ اجرت را نگه میدارد — همان چیزی که دفترِ فی مینامیم (بخش ۳۹ هم رویش بسته شده). دفعهٔ بعد که همان قلم را برای همان شخص میزنی، عدد خودش میآید و یک پیام کوتاه میگوید از کجا آمده.
قاعدهٔ سختِ این دفتر: ردیفِ مرجوعی هرگز واردش نمیشود.
بدونِ این قاعده، مرجوعیِ ٪۶ میشد آخرین رکوردِ انگشتر مروارید و دریافتِ بعدی هم ٪۶ پیشنهاد میداد — در حالی که نرخِ واقعیِ کارِ این سازنده همان ٪۱۲ است. ٪۶ درصدِ یک توافقِ موردی برای پسدادن بود، نه نرخِ خرید.
| بعد از این کار | دفعهٔ بعد که «دریافت انگشتر مروارید» بزنی |
|---|---|
| دریافتِ ٪۱۲ | ٪۱۲ ✅ |
| پرداخت مرجوعیِ ٪۶ | باز ٪۱۲ ✅ — مرجوعی دفتر را تکان نمیدهد |
| ثبتِ غلط: پرداختِ عادیِ ٪۶ | ٪۱۲ ✅ — دفترِ «دریافت» و دفترِ «پرداخت» جدایند |
یک جا از کیمیا جلوتریم. در کیمیا آن ٪۶ در دفترِ فیِ جنس ذخیره میشود و ویدئوی مرجع میگوید برای اصلاحش «باید یک بار سند دریافتِ این جنس را با ٪۱۲ ثبت کنی تا درست شود» — یعنی یک سندِ الکی برای تعمیرِ یک عدد. اینجا نوعِ سند بخشی از کلیدِ دفتر است، پس عددِ سندِ پرداخت هیچوقت به دفترِ دریافت راه ندارد و آن سندِ الکی لازم نمیشود. این دلیلِ کنار گذاشتنِ قاعدهٔ مرجوعی نیست. اگر همان ٪۶ را با تشخیصِ عادی داخلِ سندِ دریافت بزنی، در دفترِ دریافت مینشیند و دقیقاً همان خرابی رخ میدهد. دو نگهبان، دو سوراخِ متفاوت را میبندند.
#خرید خالص: دریافتی منهای مرجوعیها
در گزارشها ← کارکرد اجناس زیرِ جدولها یک جدولِ «خالص» هست. تعریفش یک جمله است:
خرید خالص = دریافتی از تأمینکننده (کارگاه، کیمیا، بنکدار) منهای مرجوعیها.
جنسی که به سازنده برگرداندهای خریدِ تو نیست. با ثبتِ درست:
| سرفصل | وزن ۷۵۰ | منهای مرجوعی | خالص |
|---|---|---|---|
| دریافت خالص | ۱۰۰٫۰۰۰ | −۳۴٫۲۲۰ | ۶۵٫۷۸۰ |
با ثبتِ غلط (پرداختِ عادی بهجای پرداخت مرجوعی) خطا دو طرفه میشود:
- از دریافتی کم نمیشود → خرید خالص ۱۰۰٫۰۰۰ میماند، ۳۴٫۲۲۰ گرم بیشتر از واقع.
- و همان وزن زیرِ سرفصلِ «پرداخت» مینشیند، جایی که هیچ ربطی به آن ندارد.
سرِ برج که گزارشِ خرید خالصِ ماه را میگیری، جنسی که هرگز نخریدهای در آمارِ خریدت نشسته است.
جدولِ خالص فقط وقتی میآید که در آن دوره مرجوعیای وجود داشته باشد — وگرنه خالص همان اصل است و حرفِ تازهای ندارد. هر چهار جفت را میسازد: دریافت خالص، خرید خالص، فروش خالص و پرداخت خالص.
در صحنهٔ ۱ اگر همهچیز درست ثبت شده باشد، پرداخت خالص آن دستبند صفر میشود: ۲۴٫۸۰۰ رفت و ۲۴٫۸۰۰ برگشت. سودِ ٪۵ِ آن پرداخت هم دقیقاً با مرجوعی خنثی میشود و سودِ دوره صفر میماند. اینکه خالص صفر دربیاید، نشانهٔ سلامت است.
#هشدارِ جهت: «از مشتری کار دریافت نمیکنی»
اگر جهتِ ردیف با نوعِ طرف حساب نخواند، هنگام ثبت یکی از این دو جمله را میبینی:
- مشتری + دریافتِ ساخته ← «از مشتری کارِ ساخته دریافت نمیکنید، به او پرداخت میکنید. اگر جنس را پس آورده، این ردیف باید مرجوعی باشد — وگرنه فیِ دریافتی و خرید خالصتان به هم میریزد.»
- کارگاه + پرداختِ ساخته ← «به کارگاه کارِ ساخته پرداخت نمیکنید، از او کار میگیرید. اگر مرجوعیِ خودِ اوست، این ردیف باید مرجوعی باشد — وگرنه درصدِ توافقیِ مرجوعی در دفترِ فی مینشیند.»
هشدار است، نه سد. ممکن است واقعاً بخواهی — «شاید حوازتون پر بشه» — پس دکمهٔ «با این حال ثبت شود» سرِ جایش است.
سه جا عمداً ساکت میماند، وگرنه هشدار پرحرف میشد و یاد میگرفتی نادیدهاش بگیری:
| حالت | چرا هشدار ندارد |
|---|---|
| ردیفِ مرجوعی | دقیقاً همان راهِ درستِ این کار است |
| آبشده (کد ۱) و متفرقه (کد ۲) | دادنِ آبشده به کارگاه برای ساخت، و خریدِ متفرقه از مشتری، کارِ هر روز است |
| سندِ خرید یا فروش | آنجا جهت معنای دیگری دارد |
یک جا از کیمیا جلوتریم. در ویدئوی مرجع تنها دلیلِ دیدنِ این جمله، غیرمجاز بودنِ آن عملیات برای آن گروهِ دسترسی است (بخش ۱۶) — یعنی اگر گروهبندی نکرده باشی، هیچ هشداری نمیبینی. اینجا هشدارِ جهت مستقل از گروهها کار میکند و هشدارِ گروه هم اگر بود، در همان پنجره بندِ خودش را دارد.
#خلاصه در یک نگاه
| کار | نوعِ سند | تشخیصِ ردیف | برچسبی که در گزارش میبینی |
|---|---|---|---|
| مغازهدار جنس را پس آورد | پرداخت (سندِ جدید) | دریافت مرجوعی (کد ۵) | دریافت مرجوعی |
| ما به سازنده پس دادیم | دریافت (سندِ جدید) | پرداخت مرجوعی | پرداخت مرجوعی |
- ردیفِ مرجوعی همیشه داخلِ سندِ جهتِ اصل مینشیند و برچسبش نامِ عملیاتِ مقابل است. «پرداخت مرجوعی» یعنی ردیفی داخلِ یک سندِ دریافت.
- ماندهٔ حساب در راهِ درست و غلط یکی است. تفاوت فقط در میانگین فیِ دریافتی، خرید خالص و دفترِ فی پیدا میشود.
- درصدِ توافقیِ مرجوعی (٪۶ در برابر ٪۱۲) واقعاً زیان است و باید در کارکرد اجناس دیده شود — ولی هیچوقت نباید نرخِ خریدِ بعدی شود.
#۴۹. فیِ فروش نقدی، فیِ نسیه و تخفیفِ خوشحساب
بخش ۴۸ گفت مرجوعی را چطور ثبت کنی تا آمار خراب نشود. این بخش یک قدم عقبتر است: عددی که در ستونِ فی و اجرت مینشیند، اصلاً از کجا میآید؟
صحنه ساده است و هر روز تکرار میشود:
«سرویس» را از کارخانهٔ زرناز با اجرتِ ٪۶ میگیرم، و همان را به مغازهدارهای خودم ٪۸ میدهم.
٪۶ نرخِ گرفتن است و ٪۸ نرخِ دادن. تا وقتی این دو را دستی میزنی هیچ مشکلی نیست — تا روزی که یکیشان را اشتباه بزنی و شش ماه بعد بفهمی.
#فیِ فروش نقدی: عددی که روی خودِ جنس مینشیند
در اطلاعات پایه ← اجناس (یا همان پنجرهٔ «جنس جدید» که از داخل سند باز میشود) دو کادر کنارِ هماند:
| کادر | چه کسی پُرش میکند | معنی |
|---|---|---|
| پیشنهاد فی نقدی | تو | اجرتِ ریالیِ هر گرم |
| درصد فروش نقدی (اجرت ٪) | تو | اجرتِ درصدیِ فروش — همان ٪۸ |
| فی دریافتی | هیچکس؛ خواندنی است | میانگینِ چیزی که خودت پرداختهای — همان ٪۶ |
از این به بعد هر بار نامِ «سرویس» را در یک سند بزنی، ٪۸ خودش میآید و یک پیامِ کوتاه میگوید از کجا آمد.
یک گودالِ بستهشده. تا نسخهٔ قبل این عدد فقط در سندِ فروش مینشست. ولی صحنهٔ بالا بنکداری است و سندش «پرداخت» است، نه «فروش» — یعنی دقیقاً همانجایی که ٪۸ به کار میآید، هیچوقت پیشنهاد نمیشد. حالا هر دو سمتِ فروش (فروش و پرداخت) این عدد را میگیرند. سندِ دریافت و خرید عمداً بیروناند: فیِ فروش نقدی نرخِ دادن است. اگر آنجا هم مینشست، ٪۸ روی خریدی میآمد که واقعاً ٪۶ بوده و پایِ خودت را خراب میکرد.
#اگر فیِ فروش نقدی را پر نکرده باشی
پنل ردیف را خالی نمیگذارد؛ همان فیِ دریافتیِ آن جنس را پیشنهاد میدهد. یعنی بدترین حالت این است که سرِ صفر بفروشی، نه اینکه عددی از هوا بیاید.
ترتیبِ کامل سه پله دارد و همیشه همین است:
| پله | منبع | کِی حرف میزند |
|---|---|---|
| ۱ | کاتالوگِ جنس — فیِ فروش نقدی / درصد فروش نقدی | همیشه، اگر پر باشد |
| ۲ | دفترِ فی — آخرین عددِ همین قلم نزدِ همین شخص با همین نوعِ سند (بخش ۴۸) | اگر کاتالوگ خالی باشد |
| ۳ | فیِ دریافتی — میانگینِ ورودیهای همان قلم | اگر آن دو هم خالی باشند |
و یک قاعدهٔ ثابت روی هر سه: چیزی که پُر است دست نمیخورد. اگر خودت درصد را زدهای، هیچ پلهای عوضش نمیکند.
یک جا از کیمیا جلوتریم. فیِ دریافتیِ کیمیا آخرین عددِ ثبتشده است. اینجا میانگینِ وزنی است. تفاوتش وقتی معلوم میشود که یک محمولهٔ کوچکِ گران بخری: ۱۰۰ گرم با ٪۶ و ۲۰ گرم با ٪۱۲. `` (۱۰۰ × ۶ + ۲۰ × ۱۲) ÷ ۱۲۰ = ٪۷ `` «آخرین عدد» میگوید پایت ٪۱۲ است و از آن به بعد هر فروشِ ٪۸ را زیان نشان میدهد — زیانی که وجود ندارد. میانگین این تله را ندارد، و مهمتر: همان عددی است که گزارشِ کارکرد اجناس رویش بسته شده، پس پیشنهادِ فی و گزارشِ سود نمیتوانند دو حرفِ متفاوت بزنند.
#فیِ نسیه: مشتریای که نقد نمیدهد
بعضی مغازهدارها نقد تسویه میکنند و بعضی سه ماه بعد. نرخِ این دو نباید یکی باشد.
در فرمِ شخص دو کادر هست:
| کادر | معنی |
|---|---|
| مازاد فی نسیه (﷼ هر گرم) | این مبلغ به فیِ ریالیِ هر جنس اضافه میشود |
| مازاد ٪ نسیه | این درصد به اجرتِ فروشِ هر جنس اضافه میشود |
مغازهداری با مازادِ ٪۲، همان «سرویس»ِ ٪۸ را ٪۱۰ میگیرد. لازم نیست برای هر مشتری یک جنس جداگانه تعریف کنی.
فیِ نسیه فقط در بنکداری کار میکند — یعنی سندِ پرداخت. در تکفروشی نسیه نداریم و همان ٪۸ سرِ جایش میماند. این عینِ حرفِ ویدئوی مرجع است.
یک جا از کیمیا جلوتریم. مازادِ نسیه فقط روی عددِ فهرستی مینشیند: کاتالوگ، یا فیِ دریافتی. هرگز روی عددی که از دفترِ فی آمده. دلیلش یک حساب ساده است. دفترِ فی همان چیزی است که دفعهٔ پیش برای همین شخص ثبت شده — و آن عدد مازادش را از قبل دارد. اگر باز هم ٪۲ رویش سوار شود: `` سند ۱: ۸ + ۲ = ۱۰ سند ۲: ۱۰ + ۲ = ۱۲ سند ۳: ۱۲ + ۲ = ۱۴ … `` پنج سند بعد، ٪۵ گرانتر از توافقت فروختهای و هیچجا هم صدایی درنیامده. ویدئوی مرجع این تله را ندارد چون اصلاً دفترِ فی و فیِ نسیه را کنارِ هم نمیگذارد؛ اینجا کنارِ هماند، پس نگهبانش هم لازم است.
#هشدارِ ناهمخوانی: «جلوی کارت را نمیگیرد»
فرض کن فیِ دریافتیِ سرویس ٪۶ است، دفعهٔ پیش هم ٪۹ زدهای، و فیِ فروش نقدیِ جنس ٪۸ است. حالا در یک ردیف ٪۹ میزنی. کنارِ همان ردیف یک نشانِ کوچک میآید:
⚠ فیِ فهرست ٪۸
همین. نه پنجرهای باز میشود، نه ثبت متوقف میشود. فقط میگوید داری گرانتر (یا ارزانتر) از فهرستِ خودت معامله میکنی. شاید عمدی باشد — این مشتری خاص است، یا این محموله فرق دارد.
چهار جا عمداً ساکت میماند، وگرنه هشدار پرحرف میشد و یاد میگرفتی نادیدهاش بگیری:
| حالت | چرا هشدار ندارد |
|---|---|
| ردیفِ مرجوعی | درصدش توافقِ موردیِ پسدادن است، نه نرخ (همان قاعدهٔ بخش ۴۸) |
| ردیفِ اجرتِ ریالی یا عددی | با درصد قابلِ مقایسه نیست |
| سندِ دریافت و خرید | آنجا فیِ فروش نقدی معیار نیست |
| جنسی که فیِ فروش نقدی ندارد | معیاری برای مقایسه وجود ندارد |
و اگر آن شخص مازادِ نسیه داشته باشد، هشدار خودش حسابش میکند: با نسیهٔ ٪۲، ردیفِ ٪۱۰ ساکت است و ردیفِ ٪۸ هشدار میگیرد. وگرنه هر سندِ نسیهای یک هشدارِ کاذب میگرفت.
#تخفیف خوشحساب: تخفیفی که وزن است، نه ریال
بخش ۳۹ «کسر و اضافه» (کد ۸) را گفت. آن ابزار ریالی است و برای تکفروشی ساخته شده: ماندهٔ نقدی را گرد میکنی یا خردهاش را میبخشی.
در بنکداری حساب وزنی است و کد ۸ کاری از دستش برنمیآید. اینجا تخفیف یعنی: «از جمعِ وزنی که این ماه به تو دادم، ٪۲٫۵ را میبخشم.»
در پابرگِ سند، هر وقت سند ردیفِ طلایی داشته باشد، دکمهٔ «تخفیف خوشحساب (کد ۹)» میآید. درصد را میزنی و تمام:
۱۲٫۵۰۰ گرمِ ۷۵۰ × ٪۲٫۵ = ۰٫۳۱۳ گرمِ ۷۵۰
یک ردیفِ تازه ساخته میشود با نامِ «اضافه — تخفیف»، عیارِ ۷۵۰، و یادداشتِ «تخفیف خوشحساب ٪۲٫۵». به قولِ ویدئو: انگار ۰٫۳۱۳ گرم مازاد روی این وزنها گرفته بودی و تخفیف خورد.
پایهٔ درصد جمعِ وزنِ ۷۵۰ِ ردیفهای طلای همان سند است — نه وزنِ خام. سندی که آبشدهٔ ۷۴۰ و ساختهٔ ۷۵۰ را با هم دارد، با وزنِ خام عددِ بیمعنایی میداد:
۱۲٫۵۰۰ (۷۵۰) + ۱۰٫۰۰۰ گرمِ ۷۴۰ → ۹٫۸۶۷ = پایهٔ ۲۲٫۳۶۷
دو چیز در پایه شمرده نمیشوند: ردیفِ مرجوعی (خودش برگشتِ یک ردیفِ دیگر است) و تخفیفهای قبلیِ همین سند (وگرنه تخفیفِ دوم روی اولی سوار میشد).
جهتِ ردیف را خودش تشخیص میدهد و از تو نمیپرسد: طرف بدهکار بود، بدهیاش کم میشود؛ طلبکار بود، از طلبش کم میشود. تخفیف همیشه به نفعِ طرفِ مقابل است.
#چرا کد ۹ و نه یک ردیفِ عادی
این مهمترین بندِ این بخش است. ردیفِ تخفیف با کد ۹ («اضافه») ثبت میشود، و کد ۹ سه خاصیت دارد که دقیقاً همان چیزی است که تخفیف لازم دارد:
| با کد ۹ ✅ | با یک ردیفِ طلای عادی ❌ | |
|---|---|---|
| ماندهٔ حساب | ۰٫۳۱۳ گرم به نفعِ طرف | هم درست است |
| گردش موجودی (کاردکس) | دیده نمیشود | ۰٫۳۱۳ گرم «سرویس» از انبار درمیآید |
| فیِ دریافتیِ آن جنس | دستنخورده | با یک ردیفِ بیفی رقیق میشود |
| سود و زیان | زیانِ ۰٫۳۱۳ گرمِ ۷۵۰ | همان، ولی قاطیِ فروش |
سطرِ اول باز هم فریبنده است — مثل بخش ۴۸، ماندهٔ حساب در هر دو حالت یکی است. تفاوت فقط در گزارشها پیدا میشود. تخفیف جنس نیست؛ هیچ فلزی جابهجا نشده. کد ۹ همان ابزاری است که «اجارهٔ طلا» (بخش ۴۴) هم با آن روی حساب مینشیند: وزنی که به حساب میرود بیآنکه چیزی از ویترین کم شود.
عددِ ویدئو ۰٫۳۱ است و اینجا ۰٫۳۱۳ درمیآید. کیمیا وزن را دو رقم گرد میکند؛ قراردادِ وزنیِ این پنل همهجا سه رقم است و اینجا هم استثنا نمیشود.
#مرکز تاریخ و ساعت ثبت اسناد (v112)
در تنظیمات، کارت «مرکز تاریخ و ساعت» سه مقدار را نشان میدهد: تاریخ و ساعت فعلی دستگاه، تاریخ شمسی متناظر و منطقهٔ زمانی مرورگر. دکمهٔ «تازهسازی زمان» برای کنترل دوبارهٔ ساعت در دسترس است.
تاریخ سند جدید از ساعت دستگاه و منطقهٔ زمانی مرورگر خوانده میشود. این مرکز ساعت سیستمعامل را تغییر نمیدهد؛ پیش از ثبت اسناد، ساعت و منطقهٔ زمانی سیستمعامل را بررسی کنید تا تاریخ روز اشتباه وارد نشود. این نمایش فقط ابزار کنترل است و هیچ سند یا ماندهای ایجاد نمیکند.
#خلاصه در یک نگاه
| میخواهی | کجا | نتیجه |
|---|---|---|
| نرخِ ثابتِ فروشِ یک جنس | اطلاعات پایه ← اجناس ← درصد فروش نقدی | در فروش و پرداخت خودش میآید |
| ببینی خودت چند خریدهای | همان فرم ← فی دریافتی (خواندنی) | میانگینِ وزنیِ ورودیها |
| مشتریِ نسیه گرانتر حساب شود | فرمِ شخص ← مازاد ٪ / فی نسیه | فقط در سندِ پرداخت |
| ٪ از کلِ وزنِ سند ببخشی | پابرگِ سند ← تخفیف خوشحساب | ردیفِ «اضافه — تخفیف» (کد ۹) |
- ترتیبِ پیشنهادِ فی همیشه کاتالوگ ← دفترِ فی ← فیِ دریافتی است، و هیچکدام عددی را که خودت زدهای عوض نمیکند.
- مازادِ نسیه فقط روی عددِ فهرستی مینشیند، نه روی عددی که از دفترِ فی آمده. وگرنه هر سند یک پله از سندِ قبلی گرانتر میشد.
- تخفیفِ وزنی با کد ۹ ثبت میشود تا در کاردکس و کارکرد اجناس دیده نشود — چون جنسی جابهجا نشده.
#۵۰. دفتر معین: گردشِ یک طرف حساب، ردیفبهردیف
بخش ۴۲ «دفتر روزانه» را گفت: امروز در مغازه چه گذشت. این بخش همان داده را از زاویهٔ دیگری میبُرد:
با این یک نفر، از اول تا حالا چه گذشت — و بعد از هر ردیف، ماندهاش چند شد؟
صحنهٔ آشنا:
بنکداری. آقای تهماسب مشتریتان است. طی چند فاکتور در تاریخهای مختلف از شما جنس گرفته، بعضی وقتها هم آبشده آورده بابت تصفیهٔ حساب. ماندهٔ این سندش بدهکار است؛ سند بعدی چون آبشدهاش وزنش بیشتر از جنسی بوده که تحویلش دادهاید، طلبکار شده. این طلب با آن بدهی… در نهایت هنوز طلبکار است. تا آخرین سندش، و ماندهٔ نهایی این مقدار میشود.
این دقیقاً همان گفتوگویی است که سرِ پیشخوان اتفاق میافتد. برای این گفتوگو جمعِ کل کافی نیست؛ باید ردیف به ردیف با هم پیش بروید.
#چطور بازش کنی
سه در به یک اتاق:
| از کجا | چطور |
|---|---|
| اشخاص و حسابها | دکمهٔ 📖 روبهروی هر نفر |
| کارت حساب (کلیک روی نام شخص) | دکمهٔ «دفتر کامل» |
| خلاصه وضعیت | کلیک روی نامِ هر بدهکار/بستانکار |
دفتر در یک سربرگ جدا باز میشود، پس میتوانی همزمان دفترِ دو نفر را کنار هم بگذاری و بینشان جابهجا شوی (بخش ۲۳). نام سربرگ هم «معین — نامِ شخص» است تا در شلوغی گم نشود.
جای مودالِ قدیمی را گرفت. تا نسخهٔ قبل، دکمهٔ «دفتر حساب» یک پنجرهٔ کوچک باز میکرد که هر سند را یک سطر نشان میداد: کد، نوع، تاریخ، مبلغ. سه چیز در آن نبود و هر سه دقیقاً همانهاییاند که طرفِ حساب سرشان بحث میکند — پس آن پنجره برداشته شد و همهٔ درها به این صفحه وصل شدند.
#سه چیزی که این دفتر میدهد
۱) ماندهٔ بعد از هر ردیف. دو ستون از بقیه جدا شدهاند و پسزمینهٔ طلایی دارند: «ماندهٔ وزن ۷۵۰» و «ماندهٔ مبلغ». عدد هر سطر یعنی بعد از این ردیف حسابتان چقدر شد — نه جمعِ سند، نه جمعِ آخر. سؤالِ «کِی رفتم روی بدهکار؟» فقط با همین ستون جواب دارد.
هر عدد یک برچسبِ کوچک دارد:
- بس = بستانکار (سبز) — او از شما طلبکار است
- بد = بدهکار (قرمز) — او به شما بدهکار است
- ۰ خاکستری = تسویه
۲) ریزِ ردیف. یک سندِ بنکداری پنج قلم دارد؛ «مبلغِ سند» یک عددِ درهم است که هیچکس نمیتواند رویش بحث کند. اینجا هر قلم خطِ خودش را دارد، با شرح، عیار و بابتش.
۳) ماندهٔ قبلی. بالای جدول یک سطرِ خاکستری هست: ماندهٔ قبلی. اگر بازهای انتخاب کردهای، این عدد ماندهٔ درست پیش از شروع بازه است. دفترِ سهماههای که از صفر شروع شود دروغ میگوید.
#بازه، جستوجو و ماندهٔ نهایی
نوار بالای جدول همان نوارِ آشنای دفتر روزانه است: انتخابِ شخص، بازهٔ آماده (امروز، این ماه، ۷ روز…) یا بازهٔ دستی، و یک کادر جستوجو که در شرح، نوع سند و کد سند میگردد.
یک قاعدهٔ مهم: بازه و جستوجو فقط پنجرهٔ دید را کوچک میکنند. ردیفِ «ماندهٔ نهایی» در پای جدول همیشه ماندهٔ کلِ حساب است، نه جمعِ چیزی که روی صفحه میبینی. بازه را میگذاری که ببینی، نه که عوض کنی چقدر طلبکاری. پس اگر ماندهٔ نهایی با کارت حساب یکی درنیامد، یعنی جایی اشکال هست — نه اینکه «بازه فرق دارد».
پای جدول سه چیز پشت سر هم میآید: جمعِ دریافتی و پرداختیِ بازه، بعد ماندهٔ نهایی به تفکیکِ طلا، ریال، هر نوع سکه و هر ارز.
#چهار کارتِ بالای صفحه
| کارت | چه میگوید |
|---|---|
| ماندهٔ طلا | با رنگ و کلمهٔ بستانکار/بدهکار/تسویه |
| ماندهٔ ریالی | همانطور |
| ردیف در این بازه | مثلاً «۱۲ از ۸۴» یعنی از ۸۴ ردیفِ کلِ حساب، ۱۲ تا در این پنجره است |
| نشاندارها | مثلاً «۷ / ۸۴» — و مهمتر، جملهاش: «با ماندهٔ نهایی میخواند» یا «هنوز نمیخواند» |
ستونِ «سند» شمارهٔ فاکتورِ همین شخص را میدهد، چون طرفِ حساب میگوید «فاکتور سومِ من»، نه «سند شمارهٔ ۳۷۵».
#واخوانی: نشاندار کردنِ ردیفها
این کارِ اصلیِ دفتر معین است.
پرینتِ حسابِ آقای تهماسب دستتان است و دفترِ معینش روی صفحه. ردیف اول را نگاه میکنید: ما فروختیم، ایشان زده خرید — درست است، نشاندارش میکنید. ردیف دوم را هر چه در لیستِ ایشان میگردید نمیبینید — از آن رد میشوید. ردیف سوم: ما زدیم پرداخت آبشده، ایشان هم زده دریافت آبشده — درست است، نشان.
روی هر ردیف که موس ببرید، کنارِ شمارهاش یک تیک ظاهر میشود. یا سادهتر: ردیف را انتخاب کنید و کلید فاصله (Space) را بزنید. ردیف رنگش متمایز میشود و یک نوارِ سبزِ باریک در لبه میگیرد.
نشانها روی همان شخص ذخیره میشوند. فردا که برگردید، دفتر همانجایی است که رهایش کردید — با یک نگاه معلوم است کدام ردیفها را بررسی کرده بودید و کدامها را نه.
چرا نشانها چندتاییاند و نه «تا کجا رسیدم»: ردیفها به ترتیب تطبیق نمیشوند. ردیف چهارم ممکن است بماند و پنجم تا دهم تیک بخورند. با یک نشانِ تکی، همان ردیفِ چهارم گم میشد — و دقیقاً همان ردیف است که اختلافِ حساب است.
#عددی که همهٔ کار به آن ختم میشود
پای جدول، درست بالای «ماندهٔ نهایی»، دو ردیفِ سبز اضافه میشود:
نشاندارها . طلا (۷ ردیف) — جمع دریافتی، جمع پرداختی، و ماندهٔ نشاندارها نشاندارها . ریال — همان سه عدد
قاعده در یک جمله:
اگر همهٔ ردیفها نشان بخورند، «ماندهٔ نشاندارها» باید با «ماندهٔ نهایی» یکی شود.
- یکی شد؟ لیستِ شما با پرینتِ ایشان میخواند. (ممکن است ترتیبشان فرق کند؛ مهم نیست.)
- یکی نشد؟ یعنی چند ردیف در پرینتِ ایشان نیست — و اختلافِ این دو عدد دقیقاً بهاندازهٔ همان ردیفهاست. حالا میدانید دنبال چه عددی بگردید.
وقتی دو عدد بخوانند، خانهٔ ماندهٔ نشاندارها یک قابِ سبز میگیرد و کارتِ چهارمِ بالای صفحه هم سبز میشود.
سلکتورِ اولِ نوارِ کلیدها هم همین کار را راحت میکند:
| گزینه | چه میکند |
|---|---|
| همهٔ ردیفها | حالت عادی |
| بینشانها | فقط ردیفهایی که هنوز تیک نخوردهاند — یعنی دقیقاً کارِ باقیمانده |
| نشاندارها | فقط تیکخوردهها |
دکمهٔ «برداشتن همهٔ نشانها» هم برای شروعِ یک واخوانیِ تازه است.
نشان روی مانده و ماندهٔ نهایی هیچ اثری ندارد — فقط علامتِ کار است. و اگر ردیفی بعداً پاک شود، نشانش بیسروصدا میافتد.
#کلیدهای نمایش
نوارِ دومِ بالای جدول شش کلید دارد. هیچکدام عدد را عوض نمیکنند، فقط شکلِ دیدن را:
خلاصهٔ سند. سندی که هفت ردیف دارد، در یکی دو خط جمع میشود: «جمع دریافتی · طلا»، «جمع پرداختی · ریال». اول روشن میکنید تا بفهمید اختلاف در کدام سند است، بعد خاموش میکنید و میروید سراغ ریزش. روی خطِ خلاصه که کلیک کنید، ریزِ همان خط زیرش باز میشود.
نشاندار کردنِ یک خطِ خلاصه یعنی نشاندار کردنِ همهٔ ریزهایش — یک منبعِ حقیقت، نه دو تا. و خطِ خلاصه فقط وقتی تیکخورده نشان داده میشود که همهٔ ریزهایش تیک خورده باشند.
موقع چاپ حواستان باشد: اگر خلاصه روشن باشد، پرینت هم خلاصه میآید. برای فرستادنِ ریزِ اسناد، اول خلاصه را خاموش کنید و بعد چاپ بگیرید.
ترتیب تاریخ. پیشفرضِ دفتر ترتیبِ ثبت است، نه تاریخ. دلیلش عملی است: فاکتورهای کاغذی به همان ترتیبی دستِ طرفِ حساب رسیده که ثبت شدهاند. اگر فاکتوری جا مانده و آن را بعداً با تاریخِ قدیمی وارد کردهاید، در دفتر ته میماند — و ماندهٔ آخرِ دفتر با آخرین فاکتوری که دستِ اوست یکی درمیآید. اگر ترتیبِ تقویمی میخواهید، این کلید را روشن کنید.
فقط تغییرات ریالی. وقتی فهمیدهاید اختلاف ریالی است، ردیفهایی که ماندهٔ ریالی را اصلاً تکان ندادهاند (جنسی که فقط وزن جابهجا کرده، آبشدهٔ دریافتی و پرداختی) فقط شلوغیاند. این کلید کنارشان میگذارد.
اجرت در ردیف جدا. اجرتِ ساخت از مبلغِ هر ردیف جدا و در یک خطِ مستقلِ ته سند جمع میشود؛ پس در ستونِ ردیف همان وزن و مبلغِ خودِ کار میماند. مجموع دستنخورده است، فقط جایش عوض میشود.
یادداشت سند در شرح. یادداشتی که روی خودِ سند نوشتهاید (مثلاً «حواله به جناب راشدی») زیرِ همهٔ ردیفهای آن سند تکرار میشود.
یادداشتِ ردیف با یادداشتِ سند فرق دارد. یادداشتِ ردیف مالِ همان یک ردیف است و همیشه میآید — چه این کلید روشن باشد چه خاموش. جستوجوی دفتر هم هر دو را میبیند، پس میتوانید بنویسید «تا این تاریخ بررسی شد» و بعداً همان را جستوجو کنید.
نام طرف مقابل در حواله. بهطور پیشفرض ردیفِ حواله فقط «حواله» نوشته میشود؛ مشتری لازم نیست بداند پولش از حسابِ کدام بنکدار آمده. اگر میخواهید نامِ طرفِ مقابل هم بیاید، این کلید را روشن کنید. داده دست نمیخورد، فقط نمایش.
فیلترِ ارز و سکه. اگر دفتر ارز یا سکه دارد، یک سلکتور اضافه میشود: «فقط امامی»، «فقط دلار»… تا وقتی اختلاف را روی یک چیزِ مشخص گیر آوردهاید، بقیه سرِ راه نباشند.
#رفتن به خودِ سند
دابلکلیک روی هر ردیف، سندش را باز میکند. مسیرِ «یک عدد مشکوک دیدم ← سندش را باز کنم ← اصلاح ← برگردم» با دو حرکت بسته میشود.
#چاپِ دفتر
دکمهٔ «چاپ دفتر» بالای صفحه، همین جدول را با سربرگِ «دفتر معین ـ نامِ شخص ـ بازه» و نامِ مغازه چاپ میکند. در چاپ همهٔ ردیفها میآیند (اسکرول برداشته میشود) و راهنمای پایینِ صفحه حذف میشود.
این همان برگهای است که موقع تسویهٔ حساب روی میز میگذاری.
#ردیفی که خودت نزدهای
اگر سندِ فروشی مالیات داشته باشد، در دفتر یک خطِ جدا میبینی: «سود فروشنده و ارزش افزوده». این ردیف را کاربر نزده، ولی در ماندهٔ طرفِ حساب هست — پس اگر نمایش داده نشود، ماندهٔ تهِ دفتر با کارت حساب یکی درنمیآید و بین دو عددِ رسمی گیر میکنی. زیرِ آن هم نوشته میشود سود چقدر بود و مالیات چقدر.
#آنچه این دفتر عمداً نمیکند
- فیلترهای دفتر روزانه اینجا نیستند (نوع سند، کاربر، جنس، عیار، انتخابهای ویژه). دفتر معین ابزارِ تطبیق است؛ یک ردیفِ حذفشده یعنی یک ماندهٔ غلط. هر چه اینجا هست — بازه، جستوجو، فیلترِ نشان، فیلترِ ارز، «فقط تغییرات ریالی» — فقط پنجرهٔ دید را کوچک میکند: ماندهٔ ستون، ماندهٔ نهایی و جمعِ نشاندارها همگی روی کلِ حساب حساب میشوند و دستنخورده میمانند.
- ماندهٔ اول دوره را نادیده نمیگیرد. اگر برای شخص «ماندهٔ اول دوره» ثبت کردهای (یا از بستن سال مالی آمده)، همان عددِ شروعِ ستونِ مانده است.
#۵۱. معکوسِ سند: خرید و فروشِ آینه با Ctrl+H
کجاست: صفحهٔ سند ← دکمهٔ «معکوس» در نوارِ ابزار، کنارِ دکمهٔ «انتقال» ← یا کلید Ctrl+H روی صفحهکلید.
سندِ فروش را برای «ایرج طهماسب» زدهای و پول را نقد گرفتهای. همین معامله از طرفِ دیگر هم یک سند است: تأمینکنندهای که این جنس را به شما فروخته («ابوالفضل جلالی») باید یک سندِ خرید همراهش ثبت شود — با همان وزن و همان فی، فقط طرفِ حساب و جهت برعکس.
#کارِ غلطی که وسوسهکننده است
سندِ دوم را از نو دستی تایپ کنی: نوع، شخص، ردیفها، وزن، عیار، فی — همهٔ همان اعداد، یکبارِ دیگر. هر تایپِ دوباره یک فرصتِ تازه برای اشتباه است، مخصوصاً وقتی وزن و فی اعدادِ ریز و اعشاریاند.
«معکوس» برای همین ساخته شده: یک سندِ آینه با همان وزن و همان فی میسازد؛ فقط نوع را برعکس میکند (فروش↔خرید، دریافت↔پرداخت) و از تو میپرسد این سند برای کدام شخص باشد. خودت فقط مظنه را عوض میکنی.
#روالِ کار
| گام | کار |
|---|---|
| ۱ | سندِ اصلی را باز کن — باید قبلاً ذخیره شده باشد |
| ۲ | دکمهٔ «معکوس» در نوارِ ابزار یا کلید Ctrl+H |
| ۳ | هشدار میآید و شخصِ مقصد را انتخاب میکنی — از لیست، یا اسمش را در کادرِ جستوجو بنویس |
| ۴ | «معکوس کن» — یک سندِ تازه و ذخیرهنشده باز میشود، پر از ردیفهای کپیشده |
| ۵ | مظنه و هر عددِ دیگری را که لازم است تغییر بده، بعد خودت ذخیره سند بزن |
سندِ آینه خودکار ذخیره نمیشود — درست مثلِ «سندِ جدید» ساختنِ مرجوعی. تا کلیدِ «ذخیره سند» را نزنی، چیزی در دفترِ حساب ثبت نمیشود؛ همیشه اول بازبینی، بعد ذخیره.
#⚠ چه چیزی کپی میشود و چه چیزی نه
ردیفها با وزن، عیار، فی و تعداد عیناً کپی میشوند — «همون مبلغ رو میاره، صرفاً مظنه رو تغییر بدی». اما چهار چیز عمداً کپی نمیشوند: یادداشتِ ردیف، شناسهٔ چک، شناسهٔ مرجوعی، و شناسهٔ کارتخوان — اینها به سندِ مبدأ قفل بودند و روی سندِ آینه بیمعنیاند. تاریخِ ردیف هم پاک میشود؛ وقتی سند ذخیره شود، تاریخِ همان روز را میگیرد.
از خودِ سند هم واحدِ قیمت، مظنه و نوعِ بانک/کارتخوان کپی میشوند؛ طرفِ حساب البته کپی نمیشود — همان چیزی است که از تو پرسیده میشود.
این ردیف هیچ ربطی به سندِ مبدأ ندارد — مثلِ حوالهٔ دوطرفه نیست. حواله و کارتخوان دو سند را با یک شناسهٔ مشترک به هم قفل میکنند: یکی را که عوض کنی، ردِ پایش روی آن یکی هم میماند. سندِ آینهٔ معکوس اینطور نیست؛ یک سندِ کاملاً مستقل است. اگر بعداً سندِ مبدأ را ویرایش یا حذف کنی، سندِ آینه (اگر قبلاً ذخیره شده) دستنخورده میماند — و برعکس.
#چه سندهایی معکوسشدنیاند
- قبلاً ذخیره شده باشد — سندِ در حالِ ویرایش دکمهٔ معکوس نمیگیرد.
- نوعش جهتِ برعکسِ روشن داشته باشد: فروش↔خرید، دریافت↔پرداخت. سندهای «سایر» معکوسِ روشنی ندارند و دکمه اصلاً ظاهر نمیشود.
- طرفِ حساب داشته باشد.
- دستکم یک ردیفِ باارزش داشته باشد — سندِ خالی چیزی برای کپی ندارد.
#چکلیستِ بعد از هر معکوس
- شخصِ مقصد را درست انتخاب کردهای؟
- مظنه و هر عددی که باید دستی عوض شود را چک کن — فقط وزن و فی از سندِ اول کپی شدهاند.
- سند را ذخیره کن؛ تا نزنی، هیچجا ثبت نشده.
جمعبندی: وقتی یک معامله همزمان دو طرف دارد — فروشِ نقدی به مشتری که همزمان خریدِ همان جنس از تأمینکننده هم هست — بهجای تایپِ دوباره، سندِ اول را معکوس کن (Ctrl+H)، شخص و مظنه را عوض کن، و ذخیره بزن.
#۵۲. ماشین حسابِ سلول: جمعِ چند وزن با کلید =
کجاست: داخلِ سند، روی سلولِ وزن، تعداد یا مبلغ (فی) کلید = را بزن — پنجرهٔ ماشین حساب همانجا باز میشود.
مشتری یک بسته انگشتر آورده تا وزنش را با هم جمع کنی؛ یا چند تکه پولخرد که باید تعدادشان را بشماری. لازم نیست بیرون از برنامه با ماشین حسابِ گوشی جمع بزنی و بعد عددِ نهایی را تایپ کنی — که هم وقتگیر است، هم اگر اشتباه شود دیگر معلوم نیست عددِ داخلِ سلول از کجا آمده.
#روالِ کار
| گام | کار |
|---|---|
| ۱ | روی سلولِ وزن (یا تعداد، یا فی) بایست و کلید = را بزن |
| ۲ | عددِ اول را بنویس و Enter (یا دکمهٔ +) — به نوار اضافه میشود |
| ۳ | عددِ بعدی… همینطور تا آخر. برای کمکردن (مثلاً وزنِ نخ یا جعبه) دکمهٔ - را بزن |
| ۴ | حاصل بالای پنجره، لحظهبهلحظه، پیدا است — با شمارِ موردها (۴ مورد) |
| ۵ | تأیید یا کلید F2 — نتیجه در سلول مینشیند |
هر عددی که وارد کردی یک «برچسب» میشود؛ اگر اشتباه زدی، ✕ رویش را بزن تا فقط همان یکی حذف شود، بیآنکه از نو شروع کنی. اگر عددی را تایپ کردهای ولی هنوز Enter نزدهای، تأیید/F2 همان را هم حساب میکند — پس عددِ آخر جا نمیماند.
#ضرب و تقسیم هم هست
سه سکه یا سه انگشترِ هموزن گرفتهای و میخواهی وزنِ کل را بدانی؟ لازم نیست سه بار همان عدد را جمع بزنی: بنویس ۳، دکمهٔ × را بزن، بعد وزنِ هر دانه (۸٫۱۳۳) را بنویس و تأیید — نتیجه ۲۴٫۳۹۹ گرم در سلول مینشیند. دکمهٔ ÷ هم برعکسِ همین کار را میکند (وزنِ کل تقسیم بر تعداد).
- روی کیبورد هم کار میکند:
*برای ضرب و/برای تقسیم. - زنجیره از راست به چپ، بهترتیبِ زدن حساب میشود — درست مثلِ نوارِ یک ماشین حسابِ رومیزی، نه با تقدمِ ضرب بر جمع. یعنی
۲ + ۳ × ۴میشود(۲+۳)×۴ = ۲۰. - تقسیم بر صفر بیاثر است و حاصل را خراب نمیکند.
#عملگرِ هر مورد را میشود عوض کرد
روی علامتِ کوچکِ کنارِ هر برچسب که بزنی، عملگرِ همان مورد میچرخد: + ← − ← × ← ÷. اگر وزنِ نخ را اشتباهی جمع زدی، بهجای پاککردن و نوشتنِ دوباره، فقط علامتش را روی − بگذار.
#پاک کردنِ آخری و بازگشت
- پاک کردنِ آخری — آخرین موردِ نوار را برمیدارد؛ میتوانی یکییکی عقب بروی تا به موردِ اشتباه برسی.
- بازگشت — اگر موقعِ پاککردن اشتباه کردی، نوار را دقیقاً به حالتِ قبل برمیگرداند. هر تغییری (افزودن، حذف، عوضکردنِ عملگر) یک پله عقب دارد.
#سه ستون، سه حالت
- وزن — گرم، با سه رقمِ اعشار.
- تعداد — عددِ صحیح؛ حاصل همیشه گِرد میشود (نیمدانه معنا ندارد).
- مبلغ (فی) — ریال.
#ممیزِ بارکدهای بازار
بعضی بارکدهای بازار وزن را بدون ممیز چاپ میکنند: روی برچسب نوشته ۵۳۳ ولی منظور ۵٫۳۳ گرم است. گزینهٔ «ممیز برای بارکدهای بازار» را که تیک بزنی، هر عددِ صحیحی که در حالتِ وزن وارد کنی خودش تقسیم بر ۱۰۰ میشود و ممیز سرِ جایش مینشیند (۵۳۳ ← ۵٫۳۳). عددی که خودت با ممیز نوشتی دستنخورده میماند. این تیک به خاطر سپرده میشود؛ دفعهٔ بعد هم روشن است تا خودت خاموشش کنی.
با تفنگِ بارکدخوان: لازم نیست بینِ اسکنها دستی+بزنی. تفنگ بعد از هر بارکد خودش Enter میفرستد و ماشین حساب همان Enter را «جمع» میفهمد؛ پس پشتِ سرِ هم اسکن کن و آخرشF2بزن.
#سلول یادش میمانَد از چه ساخته شده
اگر نتیجهٔ یک سلول از دو مورد یا بیشتر ساخته شده باشد، کنارِ آن سلول یک نشانِ کوچک مثلِ Σ۴ میبینی. موس را رویش نگهداری، ریزِ همان زنجیره (۵٫۳۴ + ۶٫۳۴ + ۴٫۴۷ − ۰٫۰۵) را نشان میدهد.
و مهمتر: اگر همان سلول را دوباره با = باز کنی، نوار سرِ جایش است — همان چهار مورد با همان عملگرها. لازم نیست از نو همه را بزنی؛ فقط موردِ اشتباه را پاک کن یا عملگرش را عوض کن و دوباره تأیید بزن. اگر سلول را دستی عوض کنی، این حافظه پاک میشود — چون دیگر آن زنجیرهٔ قبلی معتبر نیست.
جمعبندی: روی سلولِ عددی کلید = را بزن، عددها را با Enter جمع، با - کم و با × و ÷ ضرب و تقسیم کن، حاصل را ببین و با F2 تأیید کن. برای بارکدهای بیممیز تیکِ بارکد را روشن کن، و بدان که سلول نوارِ کاملِ ورودیها را برای دفعهٔ بعد نگه میدارد.
#۵۳. شمارهٔ دوم و تصفیه با متفرقه
#شمارهٔ دوم
کجاست: سربرگِ سند، کنارِ تاریخ، فیلدِ «شمارهٔ دوم».
شمارهٔ سند (d_code) شمارهٔ خودِ ماست — پشتِ سرِ هم و خودکار. اما گاهی طرفِ حساب (کارگاه، بنکدار، ذوبخانه) خودش هم برای همان معامله یک شماره یا کدِ فاکتور دارد. اگر یک روز حسابها جور درنیامد، تطبیق دادنِ سندِ ما با فاکتورِ کاغذیِ او راحتتر است وقتی همان شمارهای که رویِ کاغذِ او نوشته شده، اینجا هم ثبت شده باشد.
- کاملاً اختیاری و آزاد (متن یا عدد، هرچه روی فاکتورِ طرف نوشته شده).
- فقط برای تطبیقِ بعدی است؛ در هیچ محاسبهای اثر ندارد و مانده را تغییر نمیدهد.
- با سند ذخیره میشود؛ هر بار که سند را باز کنی، سرِ جایش هست.
#تصفیه با متفرقه
کجاست: پای سند، زیرِ ماندهٔ طلاییِ زندهٔ طرف حساب — وقتی مانده صفر نیست، دکمهٔ «تصفیه با متفرقه» خودش ظاهر میشود.
کارگاه طلای خام تحویل داده و شما هم مقداری پرداختهاید؛ تهماندهٔ کوچکی از وزن باقی مانده که باید با یک تکه طلای متفرقه (کد ۲) بسته شود. راهِ قدیمی این بود که ماندهٔ روی صفحه را نگاه کنی، با ماشینحساب وزنِ دقیقِ لازم را دربیاوری، بعد دستی یک ردیفِ متفرقه بسازی — و اگر یک رقم اشتباه تایپ میشد، مانده دیگر صفر نمیشد.
با این دکمه لازم نیست هیچکدام از اینها را دستی انجام بدهی:
| گام | کار |
|---|---|
| ۱ | ماندهٔ طلاییِ سند را نگاه کن — همان کارتِ «مانده طلایی» پای صفحه |
| ۲ | اگر صفر نیست، دکمهٔ «تصفیه با متفرقه» را میبینی، با وزنِ دقیقِ لازم رویش نوشته شده |
| ۳ | کلیک کن — یک ردیفِ متفرقه با همان وزن و عیارِ پایه (۷۵۰) به سند اضافه میشود |
| ۴ | ماندهٔ طلایی همان لحظه صفر میشود |
- جهتش را خودِ برنامه از روی مانده تشخیص میدهد: طرف طلبکار بود؟ متفرقه به او میدهی. طرف بدهکار بود؟ متفرقه از او میگیری. لازم نیست خودت بین ورود و خروج تصمیم بگیری.
- روی هیچ نوعِ خاصی از سند قفل نیست — در فروش، خرید، دریافت، پرداخت یا سایر، هرجا ماندهٔ طلایی باشد، همین دکمه هست.
- اگر مانده از قبل صفر باشد، دکمه اصلاً نشان داده نمیشود.
- این ردیف مثلِ هر ردیفِ متفرقهٔ دیگر است — بعداً هم میتوانی وزن یا عیارش را دستی ویرایش کنی.
جمعبندی: «شمارهٔ دوم» شمارهٔ فاکتورِ طرفِ مقابل را کنارِ شمارهٔ خودمان نگه میدارد؛ «تصفیه با متفرقه» تهماندهٔ طلایی را با یک کلیک، بدون ماشینحساب، دقیقاً صفر میکند.
#۵۴. مرجوعیِ شناسنامهدار: همان آبشده و همان چک، نه یکی شبیهِ آن
کجاست: داخلِ سند — ردیفی که تشخیصش را روی «مرجوع» میگذاری، خودش یک نوارِ بنفش زیرِ دستت باز میکند. کنارِ آن دو گزارشِ تازه: تبِ «شناسنامهٔ آبشده» در دفتر ذوب، و ستونِ «موجود برگشتی» و دکمهٔ «زندگینامه» در دفتر چک.
#مسئله: مرجوعی که مثلِ معاملهٔ تازه ثبت میشود
آبشدهای را با بابتِ تصفیه به کارخانه دادهای. چند روز بعد پسش میفرستد — یا شکسته، یا عیارش مشکل داشت، یا هر دلیلِ دیگر. حالا همان طلا دارد برمیگردد.
راهِ ساده و غلط این است که یک ردیفِ «دریافتِ آبشده» بزنی. مانده درست درمیآید، ولی سه چیز خراب میشود:
| چه چیزی خراب میشود | چرا |
|---|---|
| پایِ خودت | دفتر خیال میکند از این کارخانه آبشدهٔ تازه خریدهای؛ میانگینِ خرید با طلایی که اصلاً نخریدهای رقیق میشود |
| فاکتور | برگهای که دستِ طرف میدهی، از مرجوعی حرفی نمیزند — دو ماه بعد سرِ همین برگه بحث میشود |
| ردِ لُنگه | آن آبشده در دفتر گم میشود: نه معلوم است از کجا آمده، نه به کجا رفته، نه چرا برگشته |
قاعده یک جمله است: مرجوعی، معاملهٔ تازه نیست. همیشه با تشخیصِ «مرجوع» ثبتش کن.
#راهِ اول: فهرستِ منبع، همانجا زیرِ ردیف
ردیف را بساز، تشخیصش را «مرجوع» بگذار و شرح را روی همان چیزی که برمیگردد بگذار (آبشده کد ۱، چکِ دیگران کد ۶، …). بهمحضِ این کار یک نوارِ بنفش زیرِ ردیف باز میشود که میگوید «مرجوعیِ چه چیزی؟».
فهرستی که باز میشود، فهرستِ همهچیز نیست. فقط چیزهایی را نشان میدهد که:
- با همین طرف حساب جابهجا شدهاند (نه کلِ دفتر)،
- جهتشان وارونهٔ همین ردیف بوده — یعنی واقعاً چیزی است که از ما رفته و حالا دارد برمیگردد،
- و هنوز کاملاً برنگشتهاند (اگر نصفش قبلاً برگشته، فقط ماندهٔ نصفِ دیگر پیشنهاد میشود).
این محدودیت عمدی و مهم است: نمیگذارد آبشدهای را که از جای دیگری گرفتهای، اشتباهی بهعنوانِ مرجوعیِ این طرف ثبت کنی.
جستوجو: کادرِ بالای فهرست هر نشانهای را قبول میکند — وزن، عیار، نامِ ریزگیری، شمارهٔ قبض، تاریخ، شمارهٔ سند. برای چک: مبلغ، شمارهٔ چک، نامِ بانک، سررسید. حتی بخشی از مبلغ کافی است، و جداکنندهٔ هزار هم اذیت نمیکند (۱،۲۵۰،۰۰۰ و 1250000 یکیاند).
اگر یادت رفت کیبورد را فارسی کنی، نگران نباش. lghdvd را هم میفهمد و «ملایری» را پیدا میکند — هر دو شکلِ لاتین و فارسی با هم امتحان میشوند، پس متنِ واقعاً لاتین هم قربانیِ این ترجمه نمیشود.
بدونِ برداشتنِ دست از کیبورد: با ↓ و ↑ بین گزینهها برو، با Enter انتخاب کن، با Esc ببند.
با انتخاب، همهٔ مشخصاتِ همان فاکتورِ اصلی سرِ جایش مینشیند — وزن، عیار، نامِ ریزگیری، شمارهٔ قبض، و برای چک: شماره، بانک و سررسید. نرخِ امروز جایگزینِ نرخِ آن روز نمیشود. بالای ردیف هم یک برچسبِ بنفش میآید که میگوید مرجوعیِ کدام ردیفِ کدام سند است.
#راهِ دوم: از خودِ سندِ اصلی
اگر سندِ اولیه دمِ دستت است، لازم نیست چیزی تایپ کنی:
| گام | کار |
|---|---|
| ۱ | واردِ همان سندِ قبلی شو و از حالتِ قفل درش بیاور |
| ۲ | روی همان ردیف کلیک کن |
| ۳ | «مرجوع شود» را بزن (یا Ctrl+R) |
| ۴ | میپرسد «همین سند یا سندِ جدید؟» — چون فاکتورِ قبلی را چاپ کرده و تحویل دادهای، معمولاً جوابْ سندِ جدید است |
| ۵ | سندِ جدید با تشخیصِ مرجوع و همهٔ مشخصات، آماده ساخته میشود |
فرقی نمیکند طرف مشتری باشد یا سازنده — همین یک کلید برای هر دو کار میکند.
#نگهبان: «این مرجوعی است، نه معاملهٔ تازه»
اگر با تشخیصِ عادی ثبت کنی و برنامه بفهمد که دقیقاً همان لُنگه (همان ریزگیری + همان شمارهٔ قبض + همان وزن) یا دقیقاً همان برگهٔ چک (همان شماره + همان مبلغ) را قبلاً خودت به همین شخص دادهای، پای سند یک نوارِ هشدار میآید:
همین آبشده (قبض ۳۳۱۲) را در سند ۱۲۰۱ به همین شخص دادهای — این «مرجوعی» است نه معاملهٔ تازه.
کنارش دکمهٔ «اصلاح کن» است: یک کلیک، تشخیص را «مرجوع» میکند و پیوندِ سندِ مبدأ را میبندد. هشدار جلوی ثبت را نمیگیرد — گاهی واقعاً همان وزن دوباره خریده شده — فقط نمیگذارد بیسروصدا از کنارش رد شوی.
#شناسنامهٔ آبشده: زندگینامهٔ یک لُنگه
کجاست: دفتر ذوب و آبشده ← تبِ «شناسنامهٔ آبشده».
هر لُنگه با نامِ ریزگیری + شمارهٔ قبض شناخته میشود. این تب هر لُنگه را یک سطر میکند و میگوید چقدرش آمده، چقدرش رفته، چقدرش هنوز نزدِ ماست، و چند بار برگشت خورده. سطر را که باز کنی، کلِ سفرش ردیفبهردیف میآید:
از حسین برزگر دریافت شد ← به امید ابراهیمی پرداخت شد ← از امید ابراهیمی دریافتِ مرجوعی شد
اسمِ هر طرف با کدش میآید، پس مستقیم میتوانی برداری و در قسمتِ اسناد جستوجو کنی. بازهٔ پیشفرض یک ماه است — عمداً، چون بازهٔ باز روی دفترِ پرکار کُند میشود. اگر لازم شد، «از سه ماه پیش»، «فقط برگشتخورده» یا «از ابتدای دوره» را انتخاب کن.
#چک: همان برگهٔ کاغذی، نه یک چکِ تازه
چکی به سازنده دادهای، برده بانک، پاس نشده، و حالا خودِ برگه را پس میآورد. این چکِ تازه نیست؛ همان کاغذِ قبلی است.
ثبتش دقیقاً مثلِ آبشده است: ردیفِ مرجوع، شرحِ چکِ دیگران (کد ۶)، و فهرستی که فقط چکهایی را میآورد که خودمان قبلاً به همین شخص دادهایم. با انتخاب، شماره و بانک و سررسیدِ همان برگه مینشیند و وضعیتش برگشتی میشود.
دو چیزِ تازه در دفتر چک:
- نشانِ «موجود برگشتی»: برگهای که رفته و برگشته، خودش این نشان را میگیرد. این وضعیت دستی ثبت نمیشود — از خودِ حرکتهای همان برگه درمیآید، پس هیچوقت با واقعیت اختلاف پیدا نمیکند.
- زندگینامهٔ برگه: روی ردیفِ چک دوبار کلیک کن (یا دکمهٔ «زندگینامه» را بزن). کلِ مسیرِ آن یک برگهٔ کاغذی میآید: «از آقای محمدی دریافت کردی ← به آقای عابدزاده پرداخت کردی ← در این تاریخ دریافتِ مرجوعی کردی.»
همین گزارش جوابِ سؤالِ بعدی را هم میدهد: این چک را از چه کسی گرفته بودم که حالا باید به او پسش بدهم؟ اسم را که دیدی، وارد سندِ همان شخص شو، روی ردیفِ دریافتِ چک کلیک کن، «مرجوع شود» را بزن و سندِ جدید بساز.
#فاکتور چه میگوید
روی برگهٔ چاپی، زیرِ ردیفِ مرجوعی یک جملهٔ کامل نوشته میشود — نه یک برچسبِ کوتاه:
این دریافت مرجوعی، برگشتِ ردیف ۲ سند ۱۲۰۱ (۱۴۰۳/۰۵/۱۲) است — قبض ۳۳۱۲ / ملایری.
پس اگر ماهها بعد سرِ همین برگه بحث شد، خودِ کاغذ جواب را دارد.
جمعبندی: مرجوعی را همیشه با تشخیصِ «مرجوع» ثبت کن؛ فهرستِ زیرِ ردیف فقط چیزهایی را میآورد که واقعاً از تو به همین طرف رفته و هنوز برنگشته، و با یک Enter همان مشخصاتِ اصلی مینشیند. اگر یادت رفت، نگهبانِ پای سند یادآوری میکند و با یک کلیک درستش میکند. «شناسنامهٔ آبشده» و «زندگینامهٔ چک» هم میگویند هر لُنگه و هر برگه از کجا آمده، کجا رفته و چرا برگشته.
#۵۵. برداشت شخصی به نامِ صاحبش: سهم شرکا از هر سه در
ویدئوی مرجع با یک جملهٔ صریح تمام میشود:
«اگر آورده یا برداشتِ شخصی تو کیمیا قبلاً در طولِ دورهتون ثبت کرده باشید، اون برداشت و آورده هم [در سهم شرکا] محاسبه بشه.»
تا پیش از این نسخه، این اتفاق نمیافتاد. دلیلش یک اشکالِ ساده ولی پرهزینه بود: برداشتِ شخصی سه راهِ ثبت داشت و گزارشِ «سهم شرکا» فقط یکی از آن سه را میدید. کاربری که راهنمای خودِ پنل را مو به مو اجرا کرده بود و برداشتش را در «مخارج مغازه» ثبت کرده بود، در گزارش عددِ صفر میدید و پنل به او میگفت هنوز کلِ سهمش را طلبکار است.
#مسئله را از کجا شروع کنیم
ویدئو سه چیز پشتِ سرِ هم میگوید و هر سه یک ریشه دارند:
- «برداشتِ شخصیتون رو به هیچ عنوان در سندِ هزینه ثبت نکنید.» چون سودِ خالص یعنی کارکردِ اجناس منهای هزینههایی که بابتِ همان سوددهی انجام شده — و پولی که شما از صندوق برمیدارید بابتِ سوددهی خرج نشده.
- «یک ردیف به خلاصه وضعیت اضافه میشود بابتِ ماندهٔ حسابهای سرمایه و برداشت، و برداشتِ شخصی را به شرطِ طلبِ مغازه نشان میدهد.»
- «برای اینکه ببینید دستِ هر شخص چقدر میگیرد، باید بروید گزارشِ سهم شرکا.»
#چه چیزی عوض شد
#۱) نامِ شریک، در همان جایی که برداشت ثبت میشود
در «مخارج مغازه»، وقتی تشخیص را روی برداشت شخصی بگذارید، پنجرهای باز میشود که به نامِ کدام شریک؟ را میپرسد و اجازه میدهد جهت را روی برداشت از مغازه یا آورده به مغازه بگذارید. بدونِ این نام، مبلغ در دفتر میماند ولی از سهمِ هیچکس کم نمیشود — و همین بود که آن ۳۴۰ میلیون را گم میکرد.
#۲) پیوندِ شریک به حسابِ شخصش
در ویرایشِ هر شریک، فیلدِ «حسابِ شخصِ این شریک» اضافه شده. اگر سندهای برداشتتان را روی حسابِ شخصیِ خودتان (با ماهیتِ «سرمایه و برداشت») ثبت میکنید، این پیوند آن دفتر را به همان شریک وصل میکند. ستونِ حساب متصل در جدولِ شرکا وضعیت را نشان میدهد و اگر حسابِ متصل حذف شده باشد، پیوندِ شکسته علامت میخورد.
#۳) گزارش، هر سه در را جمع میکند و میگوید از کجا
جدولِ «سهم شرکا» حالا دقیقاً شکلِ ویدئو را دارد: دو سطرِ سرِ فهرست برای استخرِ طلا و ریال، و بعد دو سطر برای هر شریک — یکی طلا، یکی ریال. زیرِ جدول برای هر شریک یک کارت هست که ریزِ منبع را میگوید: چقدر از دفترِ خودش، چقدر از سندِ حسابِ شخصِ متصل، چقدر از دفترِ مخارج.
#۴) ستونِ طلا دیگر دور ریخته نمیشود
تا پیش از این، ماندهٔ حسابهای امانت و سرمایه فقط ریالی خوانده میشد. یعنی اگر شریکی بیست گرم آبشده از حسابِ سرمایه برمیداشت، آن بیست گرم نه در ماندهٔ حسابش دیده میشد و نه در «خلاصه وضعیت» — از دفتر بخار میشد. حالا ستونِ طلا هم خوانده میشود و سهمِ طلاییِ هر شریک هم برداشت کم میکند. (در مغازهٔ طلا این کمبود پرهزینهتر از کمبودِ ریالی است.)
#۵) خلاصه وضعیت، گروهشده بر اساسِ ماهیت
بالای جدولِ تفصیلیِ «خلاصه وضعیت» یک نوارِ کارت آمده که ماندهها را بر اساسِ ماهیت جمع میزند — بنکداری، تکفروشی، بانک، سرمایه و برداشت، چک، … . کارتِ سرمایه و برداشت عمداً رنگِ متفاوت دارد، چون کلِ حرفِ این ویدئو همان است: تا وقتی این سطر را جدا نبینید، معلوم نمیشود چه بخشی از «وضعیتِ خوبِ» مغازه در واقع برداشتِ تسویهنشدهٔ خودتان است.
#۶) اصلاحِ علامتِ ماندهٔ حسابهای ویژه
این نکتهٔ فنی ولی مهم است. حسابِ بانکی یک ظرفِ پول است: دریافت پول را تویش میریزد، پرداخت از تویش برمیدارد. ولی حسابِ امانت و سرمایه ظرفِ پول نیستند، رابطهاند. وقتی شریک بیست میلیون برمیدارد، سندش «خروج» است ولی آن بیست میلیون طلبِ مغازه از اوست، نه بدهیِ مغازه.
پنل تا نسخهٔ پیش هر دو را یکجور حساب میکرد، در حالی که برچسبِ خودِ جدول («بدهکار/بستانکار»)، تهحسابِ اول دوره و ستونهای «خلاصه وضعیت» همگی علامتِ عکس را فرض میکردند. نتیجهاش این بود که یک برداشت دو بار از وضعیتِ مغازه کم میشد: یک بار از صندوق، یک بار در ستونِ بدهی.
حالا درست شده. برداشت همزمان صندوق را کم و طلب را زیاد میکند و این دو خنثی میشوند — یعنی برداشت، ثروتِ مغازه را نمیسوزاند، فقط جابهجایش میکند. این دقیقاً همان چیزی است که ویدئو با «به شرطِ طلبِ مغازه نشون میده» توصیف میکند.
اگر در زبانهٔ «امانات» یا «سرمایه و برداشت» حسابِ گردشدار دارید، عددشان با این نسخه علامت عوض میکند و درست میشود. یک بار نگاهشان کنید؛ تهحسابهای اول دوره دست نخوردهاند.
#عددِ خودِ ویدئو
استخر: ۷۰۱٫۷۰ گرمِ ۷۵۰ و ۴٬۳۶۰٬۵۶۰٬۰۰۰ ریال.
| شریک | ٪ | سهم طلا | سهم ریالی | برداشت | خالص |
|---|---|---|---|---|---|
| اول | ۷۰٪ | ۴۹۱٫۱۹ گ | ۳٬۰۵۲٬۳۹۲٬۰۰۰ | ۳٬۴۰۰٬۰۰۰٬۰۰۰ | −۳۴۷٬۶۰۸٬۰۰۰ |
| دوم | ۳۰٪ | ۲۱۰٫۵۱ گ | ۱٬۳۰۸٬۱۶۸٬۰۰۰ | ۷۵۰٬۰۰۰٬۰۰۰ | +۵۵۸٬۱۶۸٬۰۰۰ |
شریکِ اول بیش از سهمش برداشته، پس کارتش قرمز میشود و میگوید «به مغازه بدهکار است». جمعِ دو خالص (۲۱۰٬۵۶۰٬۰۰۰) دقیقاً برابرِ استخر منهای کلِ برداشتهاست — یعنی هیچ ریالی گم یا اضافه نشده.
#۵۶. تسویه با آبشده: با لُنگهٔ واقعیِ انبار، نه یک متفرقهٔ ساختگی
کجاست: پای سند، درست کنارِ «تصفیه با متفرقه» — وقتی ماندهٔ طلاییِ طرف صفر نیست و در انبار آبشدهای موجود است، دکمهٔ «تسویه با آبشده» خودش ظاهر میشود.
«تصفیه با متفرقه» (بخش ۵۳) تهماندهٔ طلایی را با یک تکه طلای ساختگیِ عیار ۷۵۰ میبندد — عددی که وزنش دقیقاً اندازهٔ مانده است، ولی پشتش لُنگهٔ واقعیای نیست. این برای تهماندهٔ کوچک عالی است، اما وقتی طرف طلبِ چند ده گرم دارد و شما میخواهید با همان آبشدههای واقعیِ توی گاوصندوق تسویهاش کنید، متفرقهٔ ساختگی جوابِ درست نیست: آبشدهای که از انبار بیرون میرود باید با عیار و شمارهٔ قبض و نامِ ریزگیریِ خودش ثبت شود تا شناسنامهاش (بخش ۵۴) دستنخورده بماند.
راهِ قدیمی این بود که خودت نگاه کنی چه لُنگههایی داری، با ماشینحساب جمعِ معادلِ ۷۵۰شان را دربیاوری تا ببینی کدام ترکیب به طلبِ طرف نزدیک است، و بعد تکتک ردیفشان کنی. این دکمه همهٔ آن را یکجا انجام میدهد.
#چهطور کار میکند
| گام | کار |
|---|---|
| ۱ | دکمهٔ «تسویه با آبشده» را بزن |
| ۲ | پنجرهای باز میشود که بالایش طلبِ طلاییِ طرف نوشته شده، و فهرستِ همهٔ لُنگههای آبشدهٔ موجود در انبار زیرش میآید |
| ۳ | برنامه خودش چند لُنگه را از پیش تیک میزند — از سنگین به سبک، تا جایی که از طلبِ طرف رد نشود |
| ۴ | هر لُنگه را میتوانی دستی تیک بزنی یا برداری؛ زیرِ کارت همان لحظه میگوید بعد از این انتخاب چقدر از طلب باقی میماند |
| ۵ | «افزودن به سند» را بزن — برای هر لُنگه یک ردیفِ آبشده با وزن، عیار و برچسبِ قبض/ریزگیریِ خودش به سند اضافه میشود |
#نکتهها
- انتخابِ خودکار عمداً از طلب رد نمیشود. اگر جمعِ لُنگهها دقیقاً به مانده نرسد، یک تهماندهٔ کوچک باقی میماند — همان را بعداً میتوانی با «تصفیه با متفرقه» ببندی یا لُنگهٔ دیگری اضافه کنی. این بهتر از آن است که با بیرونبردنِ یک لُنگهٔ بزرگ، طرف را بیجهت بدهکار کنی.
- آبشده همیشه «خروج» است — طلا از مغازه بیرون میرود. برچسبِ بالای پنجره از روی مانده میگوید طرف طلبکار است یا بدهکار، ولی جهتِ ردیف در هر نوع سندی (فروش، خرید، دریافت، پرداخت، سایر) یکسان میماند.
- جستوجو: کادرِ بالای فهرست وزن، عیار، نوع، شمارهٔ قبض یا نامِ ریزگیری را قبول میکند؛ جداکنندهٔ هزار و ارقامِ فارسی هم اذیت نمیکنند.
- موجودی بهطور خودکار کم نمیشود. این دکمه فقط ردیفِ سند میسازد، دقیقاً مثلِ بقیهٔ ثبتها؛ کمشدنِ لُنگه از انبار مثلِ همیشه از مسیرِ عادیِ کاردکس و دفتر ذوب دنبال میشود.
- اگر انبار آبشدهای نداشته باشد، دکمه اصلاً نشان داده نمیشود — همانجا فقط «تصفیه با متفرقه» میماند.
جمعبندی: «تصفیه با متفرقه» تهماندهٔ کوچک را با یک عددِ ساختگی صفر میکند؛ «تسویه با آبشده» طلبِ بزرگتر را با لُنگههای واقعیِ انبار میبندد و هر لُنگه با شناسنامهٔ خودش ثبت میشود.
#۵۷. سندِ عقبتاریخ (جامونده): وقتی شمارهٔ سند و تاریخش همسو نیستند
کجاست: زیرِ کادرِ تاریخِ سند (یک راهنمای آبیِ آرام)، و بهصورتِ چیپِ کوچکِ «عقبتاریخ» کنارِ شمارهٔ سند در دفتر روزانه و در دفتر معین (وقتی «به ترتیب تاریخ» روشن است).
گاهی سندی را دیرتر ثبت میکنی که تاریخش عقبتر از سندهای قبلی است — مثلاً امروز یادت میافتد یک فاکتورِ هفتهٔ پیش را ثبت نکردهای. آن سند شمارهٔ بزرگتری میگیرد (چون آخر ثبت شده) ولی تاریخش مالِ عقب است. سؤالِ همیشگی این است: «حالا این وسطِ دفتر گم نمیشود؟ باید شمارهٔ سندها را دستکاری کنم؟»
نه. پنل هر دو دفتر را بر اساسِ تاریخِ سند میچیند، نه شمارهٔ ثبت. پس سندِ جامونده خودش میرود سرِ جای واقعیِ تاریخش مینشیند — درست بینِ همان دو سندی که باید. نیازی به تغییرِ شمارهٔ سند نیست و نباید هم دست بزنی؛ شماره فقط ترتیبِ ثبت را نگه میدارد.
#پنل چهطور کمکت میکند
| کجا | چه میبینی |
|---|---|
| پای خودِ سند | تا تاریخی میگذاری که سند را عقبتر از یک سندِ قدیمیتر میبرد، زیرِ کادرِ تاریخ یک یادداشتِ آبی روشن میشود: این سند عقبتاریخ است و در دفترها قبل از سندِ فلان (با تاریخش) نشان داده میشود. |
| دفتر روزانه | کنارِ شمارهٔ آن سند یک چیپِ کوچکِ «عقبتاریخ» میآید تا با یک نگاه بفهمی این ردیف سرِ جای تاریخش نشسته، نه ته فهرست. |
| دفتر معین | همان چیپ فقط وقتی ظاهر میشود که فهرست را روی «به ترتیب تاریخ» گذاشته باشی (چون در حالتِ ترتیبِ شماره، سند طبیعتاً ته میماند). |
#نکتهها
- این فقط یک آگاهسازی است، نه یک کارِ اضافه. چیدمانِ درست از قبل انجام میشد؛ حالا پنل پیشدستانه به تو خبر میدهد تا نگرانِ «جاافتادن» نباشی.
- سندی که اولین سند است، یا تاریخش با شمارهاش همسوست، عقبتاریخ شمرده نمیشود و چیپ نمیگیرد.
- سندِ بدونِ تاریخ هرگز عقبتاریخ محسوب نمیشود.
- میخواهی گزارشت واقعاً به ترتیبِ تاریخ باشد؟ در دفتر معین کلیدِ «به ترتیب تاریخ» را روشن کن؛ دفتر روزانه همیشه بر اساسِ تاریخ است.
جمعبندی: سندِ عقبتاریخ یعنی «دیر ثبت شد، ولی مالِ عقب است». پنل خودش سرِ جای تاریخش میگذاردش و با یک راهنما و چیپِ کوچک بهت خبر میدهد — بیآنکه لازم باشد به شمارهٔ سند دست بزنی.
#۵۸. مسیر کنترل و بستن روز: از ماندهها تا سود واقعی
کجاست: صفحهٔ خلاصه وضعیت، بلافاصله زیرِ عدد بزرگ «کل وضعیت مغازه». یک نوار چهارمرحلهای با وضعیت سبز/هشدار که هر مرحلهاش بازشدنی است.
عددِ کل وضعیت بهتنهایی کافی نیست. پیش از بستن روز باید مطمئن شوی دادههایی که این عدد از آنها ساخته شده درستاند و گزارش سود و زیان نیز همان وضعیت را توضیح میدهد. پنل این کنترل را به یک مسیر روشن تبدیل کرده است:
| مرحله | چه چیزی کنترل میشود | با کلیک چه میبینی |
|---|---|---|
| ۱. کنترل ماندهها | همهٔ حسابهای دارای مانده، ردیفبهردیف | نام حساب، نوع، ارز، ماندهٔ ریالی و ماندهٔ طلایی. برای اشخاص، نامِ همان شخص در جدول پایین به دفتر معین و منشأ بدهکاری/بستانکاری وصل است. |
| ۲. کنترل موجودی | طلای فیزیکی، نقد و چک، ارز و جمع دارایی فیزیکی | چهار عدد اصلی برای تطبیق با شمارش واقعی ویترین، آبشده، صندوق، چک و ارز. |
| ۳. کل وضعیت | حاصلِ «طلبها − بدهیها + موجودی» | مبلغ ریالی، نرخ روزِ مبنا و معادل نهایی به گرم ۷۵۰. |
| ۴. تطبیق سود و زیان | کل سود و زیانِ بازهٔ «همه» در برابر کل وضعیت | هر دو عدد و اختلافشان به گرم ۷۵۰؛ دکمهٔ مستقیم برای رفتن به گزارش سود و زیان با بازهٔ «همه». |
#معنی وضعیت نهایی
- آمادهٔ بستن: نرخ روز موجود است و اختلافِ «سود و زیان از ابتدا» با «کل وضعیت» کمتر از یک گرم است.
- نیازمند بررسی: نرخ روز موجود نیست، یا اختلاف یک گرم و بیشتر است. در این حالت پنل محتملترین علتها را یادآوری میکند: ماندهٔ اول دوره، موجودیِ دستیِ بهروزنشده، فروش بدون موجودی، برداشت ثبتنشدهٔ شرکا یا ارزِ بدون نرخ.
نرخ یکسان مهم است. کل وضعیت و گزارش سود و زیان باید با یک نرخِ گرم ۷۵۰ سنجیده شوند؛ وگرنه اختلافِ ظاهری میسازند حتی اگر ثبتها درست باشند.
#طراحی و دسترسپذیری
- هر مرحله یک دکمهٔ واقعی با هدف لمسی بزرگ، حالت hover/focus واضح و پشتیبانی صفحهکلید است.
- در موبایل مسیر از چهار ستون به یک ستون تبدیل میشود و اسکرول افقی نمیسازد.
- رنگ تنها نشانه نیست؛ متنِ «آمادهٔ بستن»، «نیازمند بررسی»، «تراز» و «مغایرت» همیشه همراه رنگ نمایش داده میشود.
- حرکتها کوتاهاند و با تنظیم
prefers-reduced-motionحذف میشوند.
جمعبندی: بستن روز دیگر یعنی دنبالکردنِ یک عددِ تنها نیست؛ اول ماندهها و موجودی تأیید میشوند، بعد کل وضعیت دیده میشود و در پایان گزارش سود و زیان باید آن را با اختلاف کمتر از یک گرم توضیح دهد.
#۵۹. متفرقه با وزن ترازو: تفکیک عیار و معادل خودکار ۷۵۰
کجاست: کالا و انبار ← موجودی آبشده و متفرقه. بالای جدول، کارت «متفرقه، به تفکیک عیار» دیده میشود.
برای ثبت طلای شکسته یا متفرقه، عددی را وارد کن که واقعاً روی ترازو دیدهای؛ آن را با ماشینحساب به عیار ۷۵۰ تبدیل نکن. پنل دو عدد را همزمان و با دو معنی جدا نگه میدارد:
- وزن ترازو: وزن فیزیکیِ پاکت؛ همان عددی که برای کنترل کشو و ترازو لازم داری.
- معادل ۷۵۰: وزن حسابداری که پنل از فرمول
وزن × عیار ÷ ۷۵۰خودش محاسبه میکند.
#روش ثبت دریافت متفرقه
- در سند مشتری، نوع ردیف را طلا و شرح را متفرقه انتخاب کن.
- در ستون وزن، وزن واقعی ترازو را بنویس.
- در ستون عیار، عیار واقعی همان متفرقه را وارد کن.
- معادل ۷۵۰ را فقط در ستون محاسبهشده ببین؛ آن را دوباره در وزن وارد نکن.
- اگر مشتری دو پاکت با عیارهای متفاوت آورده، هر عیار را در ردیف جدا ثبت کن.
مثال: ۷۰۴ گرم متفرقه با عیار ۷۴۰ روی ترازوست. وزن را ۷۰۴ و عیار را ۷۴۰ ثبت کن. پنل معادل ۷۵۰ را حدود ۶۹۴٫۶۱۳ گرم نشان میدهد. اگر بهجای وزن واقعی همین معادل را ثبت کنی، موجودی نرمافزار دیگر با ترازو نمیخواند.
#کارتهای تفکیک عیار
پنل برای هر عیار یک کارت جدا میسازد. روی هر کارت میبینی:
- عیار واقعی؛
- جمع وزن فیزیکی همان عیار؛
- معادل خودکار ۷۵۰؛
- تعداد ردیفهای تشکیلدهندهٔ موجودی.
با کلیک روی کارت، مستقیم به گردش موجودی همان عیار میروی تا ببینی متفرقه از کدام سند آمده، کجا خرج یا ذوب شده و مانده چگونه ساخته شده است. بالای کارتها نیز جمع کل وزن واقعی و جمع معادل ۷۵۰ نمایش داده میشود.
قاعدهٔ طلایی: وزن واقعی برای تطبیق با ترازوست؛ معادل ۷۵۰ برای حسابداری. پنل هر دو را کنار هم نشان میدهد، اما هیچوقت یکی را جای دیگری ثبت نکن.
جمعبندی: هر عیار پاکت خودش را دارد، وزن ترازو دستنخورده ثبت میشود و معادل ۷۵۰ بدون ماشینحساب بهدست میآید؛ بنابراین هم حساب مشتری درست است و هم موجودی فیزیکی با ترازو تطبیق دارد.
#۶۰. ماندهٔ سنگ و نگین: انبارِ نگین که روی لیبل بسته میشود
کجاست: کالا و انبار ← موجودی اجناس. بالای جدول، کارت «ماندهٔ سنگ و نگین» دیده میشود — درست بالای کارتِ «ماندهٔ مادّهٔ همراه».
نگین ردیفِ جداگانهٔ انبار نمیشود. وزنش از وزنِ لیبل کسر شده و مبلغش روی همان ردیفِ طلا سوار است؛ پس اگر جایی جمعِ ورود و خروجِ نگینها ساخته نشود، هیچوقت نمیفهمی «چقدر عقیق و فیروزه توی ویترین مانده». این کارت همان جمع را از خودِ اسناد میسازد: هر ردیفی که در آن سنگ فعال است، بهاندازهٔ جهتِ سندش (ورود یا خروج) در دفتر مینشیند.
#ستونهای کارت
| ستون | یعنی چه |
|---|---|
| نگین | نامِ سنگ، بهعلاوهٔ برچسبِ روشِ قیمتگذاریاش (فقط مبلغ یا قیراطی) |
| ماندهٔ وزن | قیراط یا گرمِ باقیمانده |
| ماندهٔ تعداد | چند دانه باقی مانده |
| وارد شده / خارج شده | جمعِ مبلغِ خرید و جمعِ مبلغِ فروش |
| ماندهٔ مبلغ | اختلافِ این دو، در ارزِ خودِ سنگ |
بالای جدول برای هر ارز یک چیپِ جمع جداست: جمعِ ماندهٔ تومان و جمعِ ماندهٔ دلار. این دو با هم جمع نمیشوند و نباید بشوند — سنگی که ۴۰۰ دلار خریدهای امروز و پارسال هم ۴۰۰ دلار است، ولی معادلِ ریالیاش هر روز با نرخِ زنده تکان میخورد. اگر انبار را ریالی نگه میداشتیم، ماندهٔ دیروز با نرخِ امروز بازنویسی میشد.
#قاعدهٔ اول: نگینِ «فقط مبلغ» — سود را روی اجرت بگذار
وقتی سنگ را با روشِ «فقط مبلغ سنگ» ثبت میکنی (عقیق، فیروزه، کارِ نگیندارِ لیبلخورده)، در کادرِ قیمت دقیقاً همان عددی را بزن که روی لیبل خورده — همان که پای خودت افتاده. سودِ سنگ را در اجرت یا «سود فروشنده» لحاظ کن.
مثالِ عددی: دوازده انگشترِ «عقیق و فیروزه» با جمعِ لیبلِ ۲٬۳۰۰٬۰۰۰ تومان دریافت کردهای. یکی را میفروشی که لیبلش ۵۰٬۰۰۰ تومان است.
- درست: در قیمتِ سنگ همان
۵۰٬۰۰۰را میزنی و ۰٫۵٪ سودِ سنگ را روی اجرت میگذاری. ماندهٔ کارت میشود ۲٬۲۵۰٬۰۰۰ — و همین عدد با جمعِ لیبلِ آن یازدهتای باقیمانده در ویترین میخوانَد. - غلط: ۵۰٬۰۰۰ لیبل + ۵۰٬۰۰۰ سود را با هم
۱۰۰٬۰۰۰میزنی. ماندهٔ کارت میشود ۲٬۲۰۰٬۰۰۰، در حالی که لیبلِ یازده انگشترِ توی ویترین ۲٬۲۵۰٬۰۰۰ است. پنل کمتر از واقعیت نشان میدهد و موجودیِ سنگ بههم میریزد.
#قاعدهٔ دوم: نگینِ قیراطی — سود را روی «فی هر قیراط» بگذار
برای سنگی که قیراطی یا دانهای قیمت میخورد، ماجرا برعکس است: انبارِ این نگین با قیراط و دانه بسته میشود، نه با مبلغ. پس بالا بردنِ فی درست است و هیچ چیزی را بههم نمیریزد.
مثالِ عددی: یک یاقوتِ ۲٫۳ قیراط به فیِ ۱۷۳٫۹۱ دلار بر هر قیراط پای خودت افتاده (جمعاً ≈ ۴۰۰ دلار). همان را به فیِ ۱۸۰ دلار میفروشی (جمعاً ۴۱۴ دلار).
- ماندهٔ وزن: صفر — ۲٫۳ قیراط آمد و ۲٫۳ قیراط رفت.
- ماندهٔ تعداد: صفر.
- ماندهٔ مبلغ: ۱۴٫۰۱− دلار — این عددِ منفی سودِ توست، نه کسری. پنل هم برای آن هشدار نمیدهد.
#نوارِ هشدارِ کسری
بالای جدول، وقتی چیزی واقعاً کم آمده باشد یک نوارِ قرمز میآید و ردیفِ مربوطه هم قرمز میشود. معیارِ هشدار به روشِ قیمتگذاری بستگی دارد:
- نگینِ «فقط مبلغ» → ماندهٔ مبلغِ منفی خطاست (یعنی سود را داخلِ قیمتِ سنگ نوشتهای، یا سنگی را فروختهای که ثبتِ ورودش نشده).
- نگینِ قیراطی/دانهای → ماندهٔ قیراط یا تعدادِ منفی خطاست (یعنی بیش از آنچه خریدهای فروختهای). ماندهٔ مبلغِ منفی در این حالت طبیعی است.
کمکِ داخلِ فرم: همین قاعده در خودِ پنجرهٔ سنگ هم، لحظهٔ ورودِ اطلاعات، زیرِ کادرها نوشته میشود و با تغییرِ روشِ قیمتگذاری عوض میشود. پس لازم نیست یادت بماند؛ سرِ همان لحظه گفته میشود.
#چند نکتهٔ ریزِ دفترِ نگین
- مادّهٔ همراه (چرم، میناکاری) در این کارت نمیآید؛ دفترِ خودش را دارد که درست زیرِ همین کارت است.
- سنگِ بینام با نامِ عامِ «نگین» جمع زده میشود.
- یک نامِ سنگ با دو ارزِ متفاوت، دو ردیفِ جدا میشود؛ قاطی نمیشوند.
- مرجوعی خودبهخود جهتش برعکس حساب میشود و سندِ «سایر» بدونِ تشخیص، اثری روی دفتر ندارد.
- کارت فقط وقتی نمایش داده میشود که در دوره حداقل یک ردیفِ سنگدار وجود داشته باشد.
جمعبندی: روشِ قیمتگذاری تعیین میکند سود کجا برود — «فقط مبلغ» → روی اجرت، «قیراطی» → روی فی. کارتِ «ماندهٔ سنگ و نگین» ابزارِ کنترلِ همین قاعده است: ماندهٔ کارت باید با جمعِ قیمتِ روی لیبلِ کارهای باقیمانده در ویترین بخوانَد.
#۶۱. مشتریان تک: یک حساب، صد مشتری
کجاست: طرف حسابها ← نوع حساب، ماهیتِ «مشتریان تک». بعد در هر سند، ردیفِ «گیرندهٔ فاکتور»؛ و برای پیدا کردنِ فاکتورهای قدیمی، دفتر معین همان حساب.
مشتریِ گذری حسابِ جاری نمیخواهد. نقدی میخرد، همان لحظه تصفیه میشود و دیگر خبری از او نیست. اگر برای هرکدام یک طرف حساب بسازی، بعد از یک ماه فهرستِ طرف حسابهایت پانصد نامِ یکبارمصرف دارد و پیدا کردنِ بنکدارِ اصلیات وسطشان کار میبرد.
راهِ درست: یک حساب به نامِ عمومیِ «مشتریان تک» بساز و همهٔ گذریها را روی همان بزن. ولی همینجا یک تناقض ساخته میشود که این بخش حلش میکند:
نامِ حساب عمومی است و همین نام روی فاکتورِ کاغذی چاپ میشود — در حالی که گیرندهٔ هر فاکتور با فاکتورِ بعدی فرق دارد.
پس در پنل، هویت از حساب جدا شده است: حساب یکی است، ولی هر سند نام و تلفن و کد ملیِ گیرندهٔ خودش را دارد.
#۱) ساختنِ حساب
در نوع حساب، ماهیتِ «مشتریان تک» را به یک عنوان بدهید (یا دکمهٔ «نوعهای استاندارد» را بزنید تا خودش ساخته شود)، بعد یک طرف حساب با همان نوع بسازید.
مهم: این ماهیت عمداً مثلِ بنکداری رفتار میکند، نه مثلِ تکفروشی. یعنی سندش با مثقال باز میشود و سودِ خودکارِ فروشنده و مالیات رویش نمینشیند. دلیلش ساده است: بنکداری که به مشتریِ گذری هم میفروشد سودش روی اجرت است نه درصدِ تکفروشی، و اگر مجبور شود سند را به گرم بزند، همانجا خطای گِرد کردن میسازد. پس «مشتریان تک» هیچ محدودیتی به سند اضافه نمیکند؛ فقط لایهٔ «این فاکتور دستِ کی رفت» را روشن میکند.
#۲) گیرندهٔ فاکتور — سه خانه، در هر سند
زیر سربرگِ سند، ردیفِ گیرندهٔ فاکتور سه خانه دارد:
| خانه | لازم؟ | چرا |
|---|---|---|
| نام گیرنده | روی این حساب عملاً بله | تنها چیزی که این فاکتور را از فاکتورِ بغلی جدا میکند |
| تلفن گیرنده | اختیاری | بعداً همان فاکتور را با موبایل پیدا میکنید |
| کد ملی گیرنده | اختیاری | برای فاکتورِ رسمی و مواردی که کد ملی لازم میشود |
روی حسابِ «مشتریان تک» این ردیف نوارِ فیروزهای میگیرد و نامِ گیرنده ستارهدار میشود. تلفن و کد ملی اجباری نیستند — اجبار کردنشان کارِ سرِ پیشخوان را کند میکند و کاربر یاد میگیرد Enterِ خالی بزند.
هر سه خانه تکمیلِ خودکار دارند. کافی است شروع به تایپِ نام کنید تا فهرستِ مشتریانی که قبلاً آمدهاند باز شود؛ یکی را که انتخاب کنید، تلفن و کد ملیاش خودکار پر میشود. همین کار با تلفن و کد ملی هم میشود: شمارهٔ موبایل را بزنید، نام خودش میآید. چیزی که خودتان تایپ کردهاید هیچوقت بازنویسی نمیشود.
#۳) دو هشدار
- «این فاکتور به نامِ کسی ثبت نشده» — تا وقتی نامِ گیرنده خالی است، زیرِ همان ردیف میآید. اگر بینام ذخیره کنید، بعداً هیچ راهی نیست بفهمید این سند مالِ کدام مشتری بوده.
- «این سند ۱۳ ردیفِ پُر دارد» — قاعدهٔ هر فاکتورِ کاغذی یک سندِ جدا است. اگر ردیفِ مشتریِ بعدی را در ادامهٔ همین سند بزنید، چاپِ فاکتور نامِ گیرندهٔ اول را برای هر دو میزند و بعداً معلوم نمیشود کدام ردیف مالِ کدام مشتری بود. آستانه عمداً بلند (۱۲ ردیفِ پُر) گرفته شده تا هشدار برای فاکتورهای واقعاً چندقلم بیخود بالا نیاید.
#۴) فاکتورِ چاپی: هر دو نام میآیند
روی کاغذ، نامِ حساب سرِ جای خودش میمانَد و گیرنده با برچسبِ «توسط:» کنارش مینشیند:
مشتریان تک
توسط: خانم صانعی
این عمدی است. نامِ حساب طرفِ قراردادِ دفتر است و گیرنده کسی که کاغذ دستش رفته؛ اگر گیرنده جای نامِ حساب بنشیند، فاکتور با دفتر نمیخوانَد. اگر نامِ گیرنده و نامِ حساب یکی باشند (مثلاً روی یک طرف حسابِ معمولی)، «توسط» چاپ نمیشود.
#۵) پیدا کردنِ فاکتورِ قدیمی
دفتر معین همان حساب را باز کنید. بالای دفتر، کارتِ «فاکتورهای مشتریانِ تک» میآید — فهرستِ همهٔ فاکتورهای این حساب با ستونهای: کد سند، تاریخ، گیرنده، موبایل، کد ملی، شمارهٔ دوم، وزن و مبلغ.
کادرِ جستوجوی بالای کارت روی هر چیزی که در جدول میبینید کار میکند:
- «صانعی» → همهٔ فاکتورهای خانم صانعی
- «۰۹۱۲۲۲۲۲۲۲۲» یا حتی «۲۲۲۲۲۲» → از روی موبایل
- کد ملی
- «۴۴۳» → کد سند
- شمارهٔ دومِ فاکتور
دابلکلیک روی هر ردیف، همان سند را در سربرگِ تازه باز میکند. فاکتورهایی که گیرنده ندارند با نوارِ کهربایی و برچسبِ «بینام» مشخص میشوند و بالای کارت هم شمرده میشوند — همانهایی که باید بروید نامشان را بگذارید.
این کارت فقط روی حسابِ ماهیتِ «مشتریان تک» ظاهر میشود و در چاپِ دفتر معین نمیآید.
جمعبندی: یک حساب برای همهٔ گذریها بساز تا فهرستِ طرف حسابها تمیز بماند، ولی نامِ گیرنده را روی خودِ سند بگذار و برای هر فاکتورِ کاغذی یک سندِ جدا بزن. آنوقت هم دفترت مرتب است، هم شش ماه بعد با یک شمارهٔ موبایل همان فاکتور را پیدا میکنی.
#۶۲. موجودی متفرقه در خلاصه وضعیت: به تفکیک عیار، از دلِ اسناد
کجاست: خلاصه وضعیت، درست زیرِ جدولِ «موجودی فیزیکی مغازه». کارتهای «موجودی متفرقه، به تفکیک عیار» با برچسبِ «منتج از اسناد».
بخشِ «موجودی آبشده و متفرقه» در کالا و انبار همان کارتهای تفکیک عیار را دارد، اما آنجا از جدولِ دستیِ موجودی میآید — عددی که خودت وارد و اصلاح میکنی. سؤالِ ویدئو این بود: «همین لحظه، بر اساسِ سندهایی که زدهام، چقدر متفرقهٔ هر عیار دستم مانده؟» جوابِ آن نباید بهروزرسانیِ دستی نیاز داشته باشد.
حالا خلاصه وضعیت این را جدا نشان میدهد. تا پیش از این، همهٔ طلا زیرِ یک خطِ درشت جمع میشد: «موجودی طلا (آبشده + ساخته + سکه)». متفرقه با هر عیار در همان عدد گم بود. کارتِ تازه، متفرقه را از خودِ کاردکس بیرون میکشد: ورودِ اسناد منهای خروجِ اسناد، عیار به عیار.
#هر کارت چه میگوید
- عیار: عیارِ واقعیِ پاکت (۷۴۰، ۸۶۰، …). هر عیار کارتِ خودش را دارد؛ متفرقهٔ ۷۴۰ با ۸۶۰ قاطی نمیشود.
- وزنِ ترازو: جمعِ ماندهٔ فیزیکیِ همان عیار — همان عددی که با کشیدنِ پاکتها روی ترازو باید ببینی.
- معادل ۷۵۰: وزنِ حسابداری که پنل با فرمولِ
وزن × عیار ÷ ۷۵۰خودش حساب میکند. - شمارِ حرکت: چند حرکتِ ورود و خروج این ماندهٔ عیار را ساختهاند.
بالای کارتها هم جمعِ کلِ معادل ۷۵۰ و جمعِ کلِ وزنِ واقعی میآید.
مثال ویدئو: عیار ۷۴۰ با ماندهٔ ۱۸۵٫۱۳ گرم (معادلِ ۷۵۰ ≈ ۱۸۲٫۶۶) و عیار ۸۶۰ با ماندهٔ ۶۱٫۱۱ گرم (معادلِ ۷۵۰ ≈ ۷۰٫۰۷)؛ جمعِ متفرقه ۲۴۶٫۲۴ گرمِ واقعی و ۲۵۲٫۷۳ گرمِ معادلِ ۷۵۰.
#کلیک روی کارت → گردشِ همان عیار
با کلیک روی هر کارت، مستقیم به گردش موجودی میروی و کاردکسِ همان عیار باز میشود: کدام سند متفرقه را آورد، کجا فروخته یا ذوب شد و ماندهٔ لحظهبهلحظه چطور ساخته شد. همینجاست که اگر عددِ کارت با شمارشِ ترازو نخواند، سندِ جاافتاده یا دوبارهثبتشده را پیدا میکنی.
چرا اینجا و نه فقط در انبار؟ چون خلاصه وضعیت جایی است که سرِ روز یک نگاه به آن میاندازی. عددِ متفرقهای که از اسناد میآید، بیآنکه چیزی را دستی بهروز کنی، همانجا کنارِ بقیهٔ موجودی دیده میشود؛ و اگر با ترازو نخواند، یک کلیک تا محلِّ اختلاف فاصله داری.
جمعبندی: موجودی متفرقهٔ خلاصه وضعیت از سندها مشتق میشود نه از جدولِ دستی، عیار به عیار جدا میماند، و هر کارت دریچهای به کاردکسِ همان عیار است تا تطبیق با ترازو یک کلیک بیشتر نباشد.
#۶۳. آب کردن طلا: برداشتِ متفرقه از موجودی، درونِ قبضِ ذوب
کجاست: ذوب و آبشده ← قبض ذوب جدید (یا ویرایشِ قبض)، جدولِ «اقلام ورودی (طلای متفرقه)».
وقتی بخشی از متفرقه را برای آب کردن میفرستی، آن طلا از دستت خارج میشود و بهجایش بعداً آبشده برمیگردد. پرسشِ ویدئو این بود: «چه چیزی و به چه عیاری رفت داخلِ بوته؟» تا این لحظه، شرحِ هر ردیفِ ورودی را باید از حفظ تایپ میکردی و عیار را دستی میزدی — و هیچ ضمانتی نبود که وزنی که میفرستی از موجودیِ واقعیِ همان عیار بیشتر نباشد.
حالا هر ردیفِ ورودی یک انتخابگرِ «+ از موجودی متفرقه…» دارد. باز که کنی، همان موجودیِ متفرقه به تفکیک عیار را میبینی — دقیقاً همان ارقامی که در خلاصه وضعیت (بخش ۶۲) از دلِ اسناد میآید، نه از جدولِ دستی:
- عیارِ هر ردیف را انتخاب میکنی؛ شرح («متفرقه عیار ۷۴۰») و عیار خودکار پُر میشوند.
- کنارِ خانهٔ وزن، حداکثرِ موجودیِ همان عیار بهعنوان راهنما نشان داده میشود.
- اگر وزنی بیشتر از موجودیِ آن عیار وارد کنی، خانه قرمز میشود و بالای جدول هشدار میآید: «وزنِ متفرقهٔ عیار … از موجودی بیشتر است.»
مثال ویدئو: لیستِ برداشت سه عیار داشت — عیار ۷۴۰ با موجودی ۲۱۱٫۶۰ گرم، عیار ۷۳۸ با ۳۷٫۳۵ گرم و عیار ۸۶۰ با ۳۶٫۹۵ گرم. عیارِ بالاتر اولِ فهرست میآید. از هر کدام هر مقدار که برای ذوب میفرستی، وارد میکنی و به ردیفِ بعدی میروی.
چرا اینجا؟ چون همان قانونِ بخش ۶۲ اینجا هم برقرار است: عددِ متفرقه باید از اسناد بیاید نه از حافظه. با برداشتِ مستقیم از موجودی، قبضِ ذوب با ماندهٔ واقعیِ متفرقه یکی میماند و «بیش از موجودی فرستادن» جلوِ چشم گرفته میشود.
بقیهٔ چرخهٔ ذوب مثل قبل است: بعد از برگشتِ آبشده، در همان قبض ریگیری را ثبت میکنی (وزن و ری واقعی)، افت/سرک حساب میشود و آبشده به موجودی افزوده میشود.
جمعبندی: انتخابگرِ برداشتِ متفرقه در ردیفهای قبضِ ذوب، عیار و شرح را از موجودیِ اسنادمحور پُر میکند، حداکثرِ در دسترس را نشان میدهد و از برداشتِ بیش از موجودی هشدار میدهد.
#۶۴. سندِ تکفروشی: برای هر مشتریِ گذری یک حساب نساز
کجاست: اشخاص و حسابها — تابلوی راهنما بالای لیست، و راهنماییِ زیرِ «نوع حساب» در فرمِ شخصِ جدید.
اگر دفترتان بنکداری است ولی گاهی به مشتریِ گذری هم میفروشید، وسوسهای هست که ویدئوی مرجع اسمش را میگذارد «اشتباهی که بعضی از دوستان انجام میدهند»: فاکتورِ آن مشتری را در نوعِ تکفروشی میزنند و به ازای هر مشتری یک حسابِ جدا میسازند. سرِ ماه، لیستِ اشخاص پُر میشود از حسابهایی که هرکدام فقط یک سند دارند و دیگر هیچوقت به کار نمیآیند.
چرا توصیه نمیشود؟ دو دلیلِ خیلی مشخص، هر دو از خودِ ویدئو:
- سود: نوعِ تکفروشی سودِ مغازه را خودش روی فاکتور مینشانَد. سودِ شمای بنکدار روی اجرت است، نه درصدِ فروش. آن درصد هرچه باشد، عددِ فاکتورتان را از واقعیت دور میکند.
- واحد: قیمتِ فروشِ تکفروشی به گرم بسته میشود، اما شما با مثقال کار میکنید. هر بار مجبورید مثقال را دستی به گرم تبدیل کنید — و همان تبدیلِ اجباری، جایی است که خطای گِردکردن و استرس ساخته میشود.
راهِ درست: یک حسابِ «مشتریان تک» (بخش ۶۱). سندش عیناً مثلِ بنکداری است — مظنه، مثقال و اجرت سرِ جایشان — و فقط نامِ گیرندهٔ هر فاکتور روی خودِ سند مینشیند. یک حساب، صد مشتری؛ لیستِ اشخاص هم تمیز میماند.
#برنامه دو جا جلویتان را میگیرد
۱) پیش از ساختنِ حساب. در فرمِ شخص جدید، وقتی «نوع حساب» را روی تکفروشی بگذارید و دفترتان حسابِ بنکداریِ فعال داشته باشد، همانجا زیرِ انتخابگر یک راهنماییِ فیروزهای میآید و پیشنهاد میدهد بهجای حسابِ جدا از «مشتریان تک» استفاده کنید — با ذکرِ همان دو دلیلِ سود و مثقال. این فقط راهنمایی است؛ اگر واقعاً مشتریِ ثابتِ تکفروشیِ خودتان است، ذخیره کنید و رد شوید.
۲) اگر از قبل ساختهاید. بالای لیستِ اشخاص یک تابلوی راهنما ظاهر میشود: «… حسابِ تکفروشیِ یکبارمصرف دارید». حسابِ «یکبارمصرف» یعنی حسابی با ماهیتِ تکفروشی که دو سند یا کمتر دارد. تابلو فقط وقتی میآید که هر سه شرط برقرار باشد:
- دفترتان واقعاً بنکداری است (دستِکم یک حسابِ بنکداریِ سنددار دارید)،
- دستِکم سه حسابِ تکفروشیِ یکبارمصرف وجود دارد،
- در زبانهٔ «همه» هستید و چیزی جستوجو نکردهاید.
روی تابلو نامِ چند حسابِ نمونه میآید؛ روی هرکدام بزنید، کارتِ حسابش باز میشود. اگر حسابِ «مشتریان تک» دارید، دکمهٔ رفتن به حساب میآید؛ اگر ندارید، دکمهٔ ساختِ حساب فرمِ شخصِ جدید را با همان نوعِ حساب از پیش انتخابشده باز میکند.
مزاحم نمیشود: دکمهٔ متوجه شدم تابلو را خاموش میکند — ولی نه برای همیشه. اگر بعداً باز هم حسابِ یکبارمصرفِ تازه ساخته شود، تابلو برمیگردد. هشداری که همیشه هست را آدم یاد میگیرد ندیده بگیرد؛ هشداری که فقط وقتی وضع بدتر شد برمیگردد را نه.
حسابِ تکفروشیِ پرکار متهم نمیشود. مشتریِ ثابتِ مغازه که ده سند دارد اصلاً در این شمارش نمیآید؛ فقط حسابهایی که بعد از یکیدو فاکتور رها شدهاند.
جمعبندی: برای مشتریِ گذری حسابِ جدا نسازید. برنامه هم پیش از ساختنِ حساب راهنمایی میکند و هم اگر الگو را در دفترتان ببیند، با یک تابلوی قابلِبستن نشانتان میدهد کدام حسابها را بیجهت ساختهاید و راهِ درست کجاست.
#۶۵. هشدار گروهها: هر گروه چه چیزی را میگیرد و چه چیزی را میدهد
کجاست: موقعِ ثبتِ سند، خودش میآید. تعریفش در تنظیمات ← گروههای اشخاص.
هر طرفِ حسابی که با او کار میکنید یک رفتارِ عادی دارد. آقای طهماسبِ سازنده را در نظر بگیرید: شما به او آبشده میدهید (پرداختِ آبشده) و از او کارِ ساخته میگیرید (دریافتِ ساخته). حالا اگر اشتباهی بزنید «دریافتِ آبشده از طهماسب»، یعنی دارید کاری را ثبت میکنید که برای یک سازنده معنا ندارد — و همانجا سکوت کردنِ برنامه یعنی خطایتان تا آخرِ ماه پنهان میماند.
برنامه این را میفهمد چون هر گروه یک قالبِ دسترسیِ جهتدار دارد: برای هر عملیات (دریافت، پرداخت، خرید، فروش، مرجوعیها) مشخص است کدام ماهیتها (آبشده، متفرقه، ساخته، پول، چک، اجرت…) مجازند. نکتهٔ تازه این است که جهت مهم است: برای سازنده، «آبشده» در ستونِ پرداخت تیک دارد ولی در ستونِ دریافت ندارد.
#وقتی چیزی بیرونِ قالب باشد
اگر ترکیبِ سندتان (مثلاً دریافت × آبشده) برای گروهِ آن شخص غیرمجاز تعریف شده باشد، هنگامِ ثبت یک تابلوی هشدار میآید:
- سرِ تابلو نامِ گروه میآید: گروه «سازنده»، با پرسشِ «از انجام این کار مطمئنید؟»
- ترکیبهای غیرمجاز را بهصورتِ نشان نشان میدهد: دریافت · آبشده.
- و میگوید کجا تعریف شده تا اگر واقعاً باید مجاز باشد، خودتان بازش کنید: تنظیمات ← گروههای اشخاص.
این هشدار جلوِ ثبت را نمیگیرد — دقیقاً مثلِ بقیهٔ هشدارهای برنامه، فقط میپرسد. اگر به هر دلیل واقعاً میخواهید همان کار را بکنید، دکمهٔ با این حال ثبت شود را بزنید و سند ثبت میشود.
#قالبهای آماده
موقعِ ساختِ گروه یک قالب انتخاب میکنید و بعد در صورتِ نیاز دستی تیکها را عوض میکنید:
- سازنده: ساخته/نیمساخته را از او میگیرید (دریافت)؛ آبشده به او پرداخت میشود و پول و اجرت هم همینطور.
- مشتری: پول از او میگیرید؛ کارِ ساخته و خدمات به او میدهید.
- آبشدهفروش: آبشده از او میگیرید؛ پول به او میدهید.
- کیفی / به انتخاب خودم: بیمحدودیت — همهچیز مجاز است.
چرا مرجوعی معاف است: ستونهای «دریافتِ مرجوعی» و «پرداختِ مرجوعی» عمداً باز میمانند. برگرداندنِ جنس همان راهِ درستِ اصلاحِ یک اشتباه است و نباید خودش هشدار بگیرد.
جمعبندی: گروهها فقط برچسب نیستند؛ رفتار دارند. اگر سندی خلافِ جهتِ عادیِ آن گروه بزنید، برنامه پیش از آنکه دیر شود میپرسد — ولی هیچوقت دستتان را نمیبندد.
#۶۶. بخش فنی (توسعهدهنده)
این بخش برای کسی است که کد را نگهداری میکند؛ کاربر عادی نیازی به آن ندارد.
#ساختار فایلها
public/admin.js— منطق ·public/admin.css— استایل ·public/admin.html— اسکلت.- داده روی سرور و مشترک بین کاربران ذخیره میشود (
persist).
#مدلِ جهت (منبع واحد حقیقت)
DIR = { فروش:-1, خرید:+1, دریافت:+1, پرداخت:-1, سایر:0 }— جهت پیشفرض هر نوع سند.rowMult(d, r)— تنها منبعِ جهتِ یک ردیف. برای «خروج» = −۱، «ورود» = +۱، «مرجوع» = −base، عادی = base.computeRowMag(r)— قدرِ مطلقِ مقدار ردیف (بدون علامت).docDelta(d)— اثر واقعی سند روی مانده؛ جمعِrowMult × computeRowMag. همهٔ ماندهها از این میآیند (از طریقapplyDelta).docTotals(d)— فقط برای نمایشِ جمعِ سند (ازcomputeRowکه علامتِ مرجوع را دارد).- اثبات سازگاری: برای ردیفهای عادی/مرجوع،
rowMult == DIR[type] × rowSign؛ پس اسناد قدیمی رفتار یکسان دارند و فقط خروج/ورودِ «سایر» تازه است.
#شرح و بابت
SHARH_CODESکدهای اطلاعاتیِ وابسته بهkind؛r.sharhفقط نمایشی، بدون اثر مالی.r.babatمتن آزاد با datalist ازBABAT_COMMON.
#مخارج
state.expenses[]؛ هر مورد{date, category, babat, amount, note, dir('out'|'in'), method, bankId, bankDocId, personal, partnerId, personalDir('out'|'in'), id, ts}.expensesTotal(period)= Σ(خروج) − Σ(ورود) بدونِ برداشت شخصی ·personalTotal(period)جدا ·expensesByBabat/expensesByCatگروهبندی.- رکورد بدون
dir/personal→ خروجِ عملیاتی (سازگاری عقبرو). - v54:
expenseSyncBankDoc(e)برای روش حواله/کارت یک سندbankKind:'bank'میسازد: خروج/برداشت →پرداخت، ورود اصلاحی →دریافت. سند باexpenseIdبه مخارج و مخارج باbankDocIdبه سند وصل است.expenseDropBankDocپیش از بازسازی در ویرایش و هنگام حذف، جفت قبلی را پاک میکند؛ خود رکورد مخارج اثر سود و زیان و سند جفت فقط اثر موجودی بانک را بر عهده دارد. - v55:
expPersonalSign(e)→ آورده −۱، برداشت +۱.personalTotalخالص شد.expenseSyncBankDocجهتِ برداشتِ شخصی را ازpersonalDirمیگیرد نهdir، پس آوردهٔ حوالهای سندِدریافتمیسازد.
#سهم شرکا و حسابهای ویژه (v55)
- اصلاحِ علامت:
specLiveVal(kind, r) = ±openAmount − acctDocDelta(kind, r.id).acctDocDeltaحساب را مثل یک ظرف میبیند (دریافت +، پرداخت −) که برایbankدرست است، ولی امانت/سرمایه رابطهاند نه ظرف. همهٔ مصرفکنندهها (specBalText، تهحسابِopenKind، ستونهایshopStatus) مثبت را «بدهکار / طلبِ مغازه» میخوانند؛ پیش از این فقط همین یک تابع وارونه بود و برداشت دو بار از وضعیت کم میشد.specLiveValوspecLiveGoldتنها مصرفکنندگانِ غیربانکیِacctDocDeltaهستند، پس اصلاح مهار شده است. acctDocDeltaGold(kind, id)/specLiveGold(kind, r)— همان محاسبه رویdocTotals(d).gold. پیش از اینt.goldبیصدا دور ریخته میشد.bankعمداً بیرون است (حسابِ بانکی گرم نگه نمیدارد).partnerDraw(p, bal)→{ rial, gold, ledger, ledgerGold, person, personGold, personName, expense }. سه در را جمع میکند:specLiveVal('capital', p)+−balances()[p.personId].rial(فضای اشخاص علامتِ عکس دارد: منفی = طلبِ مغازه) +partnerExpDraw(p.id). آرگومانِbalاختیاری است تا گزارشbalances()را برای هر شریک دوباره نسازد.orphanPersonalDraw()— برداشتِ شخصیِ بدونِpartnerId؛ در گزارش هشدارِ قرمز با میانبرِdata-goexpمیشود.partnerPerson(p)— حسابِ شخصِ متصل ازp.personId؛nullیعنی پیوندِ شکسته.- خلاصه وضعیت: هر ردیفِ
accRowsیکgrpدارد (ماهیتِ شخص، یاkindبرای حسابهای ویژه، یا'chk').accGrpOrder/accGrpTitle/accGroupRowsنوارِ کارتِ «ماندهحسابها به تفکیک ماهیت» را میسازند و همان ترتیب روی جدولِ تفصیلی هم اعمال میشود. - تست:
scripts/test-partner-share.js— علامتِ حساب، ستونِ طلا، هر سه در، خنثیبودنِ برداشت در کلِ وضعیت، و بازسازیِ عددبهعددِ گزارشِ ویدئو (۷۰۱٫۷۰ گ / ۴٬۳۶۰٬۵۶۰٬۰۰۰ ﷼ / ۷۰:۳۰ → −۳۴۷٬۶۰۸٬۰۰۰ و +۵۵۸٬۱۶۸٬۰۰۰).
#موجودی متفرقه بر اساس وزن ترازو (v59)
motefDashboardData(rows)فقط ردیفهایی را میگیرد کهmeltGroupOf(type) === 'motefarreghe'است، آنها را بر اساسkaratگروهبندی میکند و برای هر گروهweightفیزیکی وw750 = weight × karat ÷ kBase()را جدا نگه میدارد.- عیار خالی با
kBase()محاسبه میشود؛ هیچ دادهٔ تازه یا وضعیتِ ذخیرهشدهای اضافه نشده و کارتها کاملاً مشتق ازstate.inv.meltsهستند. motefDashboardHtml(rows)کارتهای تفکیک عیار و جمع کل را بالایinvTblMelts()میسازد. هر کارت باdata-kxjumpبه همان کلیدstkKey('motefarreghe', type, karat)و کاردکس موجودی وصل است.- عنوان ستونهای جدول به «وزن ترازو» و «عیار واقعی» تغییر کرده تا ورودی فیزیکی با خروجی محاسباتی اشتباه نشود؛ منطق سند و موجودی قبلی تغییری نکرده است.
- استایلهای
.motef-board/.mtf-*شبکهٔ منعطف، هدف لمسی، focus-visible، حالت تیره، شکست موبایل و کاهش حرکت را پوشش میدهند. - تست:
scripts/test-motef-scale.js— گروهبندی عیار، وزن واقعی، معادل ۷۵۰، حذف آبشده از کارتها، اتصال کاردکس و قراردادهای رابط و CSS.
#مسیر کنترل و بستن روز (v58)
statusCloseData(S)گزارشperfReport('all')را باshopStatus()روی همان نرخِ روز مقایسه میکند؛Math.abs(diff) < 1معیارِ تراز است و دقیقاً یک گرم پذیرفته نمیشود.statusCloseHtml(S)چهار مرحلهٔ ماندهها، موجودی، کل وضعیت و تطبیق را از دادهٔ زنده میسازد؛ هیچ وضعیتِ تأیید دستی ذخیره نمیشود تا تغییرِ یک سند یا نرخ فوراً نتیجه را تازه کند.statusCloseOpen(k)جزئیات هر مرحله را در مودال باز میکند و CTA گزارش،reportPeriod='all'را پیش از رفتن بهreportsاعمال میکند.- استایلهای
.close-path/.cp-*شبکهٔ چهارستونه، حالتهای متنیِ تراز/مغایرت، فوکوس صفحهکلید، شکست تکستونهٔ موبایل وprefers-reduced-motionرا پوشش میدهند. - تست:
scripts/test-close-path.js— مرزِ کمتر از یک گرم، نبود نرخ، اتصال چهار مرحله، مسیر گزارش، واکنشگرایی، فوکوس و کاهش حرکت.
#موجودی متفرقه در خلاصه وضعیت (v62)
- تفاوت با v59: آن کارتها از
state.inv.melts(جدولِ دستیِ انبار) میآمدند؛ اینها از کاردکسِ مشتقازسند میآیند تا خلاصه وضعیت بدونِ بهروزرسانیِ دستی، ماندهٔ متفرقهٔ هر عیار را نشان دهد. motefStockByCarat()خروجیِstkSubjects()را بهgroup === 'motefarreghe'فیلتر میکند، آنها را بر اساسayarگروه میکند (چند نامِ همعیار زیرِ یک کارت جمع میشوند)، برای هر گروهstkLedger(keys, {})را روی کلِ دوره میگیرد و ماندهٔclose.vazn/close.w750را برمیدارد. عیارهایی که هر دو ماندهٔشان زیرِ0.0005است حذف میشوند. خروجی نزولی بر اساس عیار مرتب و همراهِ جمع کل است.motefStatusPanelHtml()بردِ کارتها را میسازد و درRENDER.summaryپس از جدولِ «موجودی فیزیکی مغازه» تزریق میشود؛ اگر متفرقهای نباشد رشتهٔ خالی برمیگرداند و هیچ پنلی اضافه نمیکند.- هر کارت
data-mtfjumpدارد که کلیدهای همان عیار را با جداکنندهٔ~~نگه میدارد؛ بایندِ[data-mtfjump]در انتهایRENDER.summaryباstkOpen(dataset.mtfjump.split('~~'))به گردش موجودی گذر میکند. عدد از همانrowW750Phys/کاردکسِ موجود میآید، پس محاسبهٔ موازی و منبعِ حقیقتِ تازهای ساخته نشده است. - استایل از همان کلاسهای
.motef-board/.mtf-*بردِ انبار بازاستفاده میشود؛ CSS تازهای لازم نبود. - تست:
scripts/test-motef-status.js— تجمیعِ عیار، اتحادِ ورود−خروج، بازسازیِ عددبهعددِ ویدئو (۷۴۰ → ۱۸۵٫۱۳/۱۸۲٫۶۶، ۸۶۰ → ۶۱٫۱۱/۷۰٫۰۷، جمع ۲۴۶٫۲۴/۲۵۲٫۷۳)، جمعِ دو نامِ همعیار در یک کارت، حذفِ عیارِ صفرشده، اتصالِ گذر به کاردکس و توکنِ کش.
#برداشتِ متفرقه از موجودی در قبضِ ذوب (v63)
- بازاستفاده از
motefStockByCarat()(همان منبعِ v62):meltMotefPicks()هر ردیفِ ماندهٔ متفرقهٔ عیار را به یک گزینهٔ برداشت نگاشت میکند با{ ayar, vazn, w750, desc: 'متفرقه عیار <ayar>', label: 'متفرقه عیار <fa> — موجودی <wt> گ' }؛ نزولی بر اساس عیار.meltMotefAvail(ayar)ماندهٔ در دسترسِ همان عیار را میدهد (۰ اگر نبود). - در
meltForm.renderIns()هر ردیفِ ورودی یک<select class="mz-pick" data-mp="i">بالای خانهٔ شرح دارد؛onchangeباreadIns()وضعیت را میخواند،work.ins[i].desc/ayarرا از گزینه پُر میکند،renderIns()میزند و فوکوس را به خانهٔ وزنِ همان ردیف میبرد. عیارِ آزادِ دستی همچنان کار میکند (انتخابگر فقط کمک است). - راهنمای حداکثر: اگر
meltMotefAvail(r.ayar) > 0باشد، خانهٔ وزنplaceholder="حداکثر <wt>"میگیرد. بیشبرداشت:sum()هر ردیفی کهvazn - avail > 0.0005باشد را با کلاسِoverقرمز و یک خطِmz-warnبالای جدول علامت میزند — فقط هشدارِ دیداری، ذخیره را مسدود نمیکند. - CSS تازه:
.mz-desc-cell(چیدنِ عمودیِ انتخابگر+شرح)،.mz-pick(سلکتِ نقطهچینِ طلایی)،.tbl.editable .cell.over(خانهٔ قرمزِ بیشبرداشت). چرخهٔ آبشدهٔ برگشتی و ریگیری (meltResultForm) بدون تغییر است. - تست:
scripts/test-melt-motef-pick.js— بازسازیِ لیستِ برداشتِ ویدئو (۷۴۰ → ۲۱۱٫۶۰، ۷۳۸ → ۳۷٫۳۵، ۸۶۰ → ۳۶٫۹۵)، ترتیبِ نزولیِ عیار، شرحِ خودکار،meltMotefAvail، جمعِ معادلِ ۷۵۰ ورودی، حذفِ عیارِ صفرشده، سیمِکشیِ انتخابگر و هشدارِ بیشبرداشت و توکنِ کش.
#نگهبانِ «هر مشتری یک حساب» (v64)
docCountByPerson()یک بار رویstate.docsمیگردد و تعدادِ سندِ هرpersonIdرا میدهد؛shopIsWholesale()میگوید آیا دستِکم یک شخصِ با ماهیتِwholesaleو سندِ ناصفر وجود دارد (یعنی دفتر واقعاً بنکداری کار میکند).retailSprawl()اشخاصِ با ماهیتِretailوdocs ≤ RETAIL_ONEOFF_DOCS(=۲) را جمع میکند و{ accounts, docs, walkin, wholesale, hit }میدهد.hitفقط وقتیtrueاست کهwholesaleباشد وaccounts.length ≥ RETAIL_SPRAWL_MIN(=۳). مرتبسازی نزولی بر اساس تعدادِ سند، سپس نام.walkinTypeTitle()عنوانِ نوعِ حسابی را میدهد که کاربر خودش به ماهیتِwalkinنگاشته (state.catalog.accountNatures)، وگرنه عنوانِ استانداردِACC_NATURES.walkinAccount()اولین شخصِ با آن ماهیت را برمیگرداند تا دکمهٔ تابلو مقصد داشته باشد.- پیشگیری:
natHintHtml(type)وقتی ماهیتِ انتخابیretailاست وshopIsWholesale()صادق، یک<span class="an-steer">به همان#f_typeNatاضافه میکند. چون کلِ span باouterHTML = natHintHtml(this.value)درonchangeبازساخته میشود، راهنمایی زندهٔ انتخابِ کاربر است و بایندِ تازهای لازم ندارد. - تابلو:
retailSprawlHtml()درRENDER.personsبینِ page-head و پنلِ جدول تزریق میشود و فقط وقتی!q && personFilter === 'همه'. حسابِ نمونهها باdata-cardمیآیند تا از همان بایندِ موجودِ[data-card] → personCard()استفاده کنند (بایندِ تازهای برای پرش ساخته نشده). فهرست به ۶ تا بریده میشود و بقیه شمرده. - خاموشیِ پویا:
state.settings.retailSprawlAckتعدادِ حسابهایی است که کاربر تأیید کرده؛ تابلو فقط وقتیaccounts.length > retailSprawlAckاست میآید.#sprawlAckاین عدد را روی مقدارِ فعلی مینشاند وpersist()میکند. #sprawlNewاگر عنوانِwalkinهنوز درstate.catalog.accountTypesنباشد آن را اضافه و باaccNatureSet(t,'walkin')نگاشت میکند، سپسpersonForm('', t). برای همینpersonForm(id, preType)یک پارامترِ دومِ اختیاری گرفت که فقط روی حسابِ جدید اثر دارد.- CSS تازه:
.an-steer(راهنماییِ نقطهچینِ فیروزهای زیرِ انتخابگر) و خانوادهٔ.advice-card/.ad-head/.ad-body/.ad-list/.ad-chip/.ad-footبا حالتِ تیره. رنگ عمداً طلاییِ ملایم است نه قرمز — این پیشنهاد است، نه خطا؛ هیچجا ذخیره را مسدود نمیکند. - تست:
scripts/test-retail-sprawl.js— آستانهها، بازسازیِ دفترِ ویدئو (بنکدار + پنج حسابِ تکسندی)، مرزها (دو حساب، مغازهٔ صرفاً تکفروش، بنکدارِ بیسند، مشتریِ تکفروشیِ پرکار)، مقصدِ پیشنهاد و عنوانِ دلخواهِ کاربر، محتوای تابلو و خاموشی/بازگشتش، حضور و غیابِan-steerروی ماهیتهای مختلف، سیمکشی و استایل و توکنِ کش.
#هشدار گروهها: قالبِ جهتدار (v65)
- تا v64 قالبِ گروهها با
permFromKinds(kinds)ساخته میشد و همان فهرست را در هر شش عملیات یکسان مینشاند — یعنی جهت (دریافت در برابر پرداخت) هیچ اثری نداشت.permMatrix(map)جایگزینش است: هر عملیات (receive/pay/buy/sell/retReceive/retPay) فهرستِ ماهیتِ خودش را میگیرد و عملیاتِ ذکرنشده «همه مجاز» میماند.permFromKindsسرِ جایش مانده (تستهای قدیمی و پُرکردنِ دستی از آن استفاده میکنند). - قالبهای آماده حالا جهتدارند. مهمترینش
sazande:receiveفقط['sakhte','gheyre','khadamat','nimsakhte']وpayشاملِabshode. پس «دریافتِ آبشده از سازنده» غیرمجاز است ولی «پرداختِ آبشده» مجاز — دقیقاً نکتهٔ ویدئو.buy.abshodeعمداًtrueوbuy.gheyreعمداًfalseمانده تا باscripts/test-books.jsسازگار بماند. docPermInfo(d)هستهٔ تشخیص است: نوعِ سند را به عملیات نگاشت میکند (فروش→sell…)، گروهِ طرف حساب را میگیرد، و برای هر ردیفrowPermKind(r)را باg.perms[op][kind] === falseمیسنجد. ردیفِtashkhis==='مرجوع'به عملیاتِ مرجوعی سوییچ میشود (که پیشفرض باز است). خروجی{ group, items:[{op,k,opLabel,kLabel}] }یاnull.docPermWarn(d)(نامش دستنخورده تاtest-fee-book.jsنشکند) حالا فقطdocPermInfoرا به یک متنِ کوتاه تبدیل میکند.permWarnHtml(info)تابلوی طراحیشده را میسازد: نامِ گروه سرِ کارت، «از انجام این کار مطمئنید؟»، نشانِ ترکیبها، و اشاره به «تنظیمات ← گروههای اشخاص». درsaveDocخطِif (warn) body += permWarnHtml(docPermInfo(d));جای خطِ متنیِ قبلی نشسته؛ دکمهٔ با این حال ثبت شودِ همان پنجره، «بله»ِ ویدئوست. جلوِ ثبت گرفته نمیشود.- CSS تازه: خانوادهٔ
.perm-warn/.pw-head/.pw-ic/.pw-title/.pw-sub/.pw-body/.pw-list/.pw-badge/.pw-footبا حالتِ تیره. رنگ طلاییِ ملایم است نه قرمز — پرسش است نه خطای فاحش. - تست:
scripts/test-group-warn.js— جهتداریِ قالبها (آبشدهٔ سازنده در دریافت/پرداخت، ساختهٔ مشتری، آبشدهفروش)، رفتارِpermMatrix، سناریوی دقیقِ ویدئو (دریافتِ آبشده هشدار میدهد، پرداختش نه)، مرزها (بیگروه، ردیفِ ساخته، سندِ نامرتبط، معافیتِ مرجوعی)، محتوای تابلو، سیمکشی و استایل و توکنِ کش.
#عیار تهحساب (v1)
- شخص یک فیلد اختیاری
settleKaratدارد (خالی = خاموش). goldAtKarat(w750, karat)=num(w750) × 750 ÷ karat؛ اگرkaratصفر/خالی باشد همانw750برمیگردد. مانده در دیتابیس همچنان طلای۷۵۰ است؛ این فقط یک نمایشِ تبدیلشده است.personCardزیرِ «ماندهٔ طلا» خطِpc-stat-convو یک chip «عیار تهحساب» نشان میدهد.factorBalStr(b, settleKarat)در فاکتور ازgoldAtKaratاستفاده میکند؛ هر دو محلِ صدا زدن حالاp && p.settleKaratرا پاس میدهند.
#گروههای دسترسی و هشدار عملیات (v2)
PERM_OPS(۶ عملیات: receive/pay/buy/sell/retReceive/retPay)،PERM_KINDS(۹ نوع کالا)،PERM_PRESETS(custom/abshode/keyfi/moshtari/sazande).- گروهها در
state.catalog.personGroups[]باperms[op][kind] = true|false؛ شخص فیلدgroupIdدارد. rowPermKind(r)نوعِ مجوزِ یک ردیف را ازkind/sharhاستخراج میکند (gold: 1/3→abshode، 2/10→motefarreqe، بقیه→sakhte؛ rial: 6→chek، بقیه→naqd؛ wage→khadamat؛ coin→arzSekke).docPermWarn(d)نوعِ سند را به base-op نگاشت میکند، برای هر ردیفِ «مرجوع» به retReceive/retPay سوییچ میکند، و اگرperms[op][kind] === falseباشد رشتهٔ هشدار میسازد. فقط هشدار است؛ ذخیره را مسدود نمیکند.
#عکس اجناس (v3)
- ذخیرهسازی: فایل روی سرور در
uploads/+ ارجاعِ URL — نه base64 در داده (برای جلوگیری از تورمِadmin_store.json). - endpointِ
POST /api/admin-uploadدرserver/server.js(بدون auth، موازیِ/api/admin-store): data-URL را parse، پسوند را باUPLOAD_EXTاعتبارسنجی، سقف ۱٫۵MB، نامِrandomUUID()+ext، و{ url: '/uploads/<name>' }برمیگرداند. goodsType.img(پیشفرضِ نوعِ جنس) وrow.img(اختصاصیِ ردیف)؛rowGoodsImg(r)اولrow.imgبعد نوعِ جنس را برمیگرداند.- کمکتابعها:
thumbHtml(url,cls)،pickImage(cb)،uploadImage(file,cb)،goodsRowImage(rowIdx)(مودال)،goodsTypeByName. - بندانگشتی در: لیستِ اجناس (
invTblGoods)، ورودِ زندهٔ سند (renderDocRows)، و فاکتورِ چاپی (factorRowDescباc-desc-img).
#پیوست سند و پشتیبان zip (v4)
ATTACH_EXT=UPLOAD_EXT+ pdf/txt/doc/docx/xls/xlsx؛ سقف ۸MB (عکسِ ساده همچنان ۱٫۵MB از مسیر/api/admin-upload).POST /api/admin-attach— بدون auth، همالگوی/api/admin-store: data-URL را parse، MIME را با whitelist چک، نامِrandomUUID()+ext، خروجی{url, size, ext}. پسوند از MIME میآید نه از نام فایل، پس نام فایل قابلسوءاستفاده نیست.d.attachments[] = {id, url, name, size, ts}؛docAttachments(d)با lazy-init. فقط نشانی ذخیره میشود، نه محتوا.GET /api/admin-backup— zip بدون فشردهسازی (method=store) باbuildZip(files)دستی و بدون وابستگی. محتویات:admin_store.json+ هر/uploads/...که در متنِ داده ارجاع شده +README.txt. انتخاب فایلها با regex روی خودِ JSON است، پس فایلهای یتیم داخل پشتیبان نمیآیند.- محافظت مسیر:
full.startsWith(UPLOADS_DIR + path.sep)جلوی path traversal را میگیرد. - سمت پنل
zipReadJson(buf, 'admin_store.json')هدرهای local-file را میپیماید و فقط ورودیِ ذخیرهشده (method 0) را میخواند؛ بازگردانی JSON خام هم پشتیبانی میشود.
#پیشنویس تکفروشی (v3)
- کاملاً جدا از
state؛ درlocalStorageبا کلیدnoqte.quote.v1و همگامسازی بین تبها باBroadcastChannel. quoteCalc(r)عمداً همان فرمولdocTaxBreakdownرا بازتولید میکند:profit = (gold+wage)×profitPct،vat = (wage+profit)×vatPct.- ردیف
kind:'trade'(طلای مشتری) باtotal = -goldوارد جمع میشود؛ اجرت و مالیات نمیگیرد. quoteToDoc()ردیفها را بهcurDoc.rowsنگاشت میکند؛ trade →tashkhis:'ورود'، درصد اجرت →wage:{mode:'percent'}.
#دفتر ذوب و آبشده (v5)
state.melts[]؛ هر قبض:{id, code, date, personId, personName, refiner, receipt, ins[], note, status, outWeight, outKarat, fee, retDate, retReceipt, invAdded, feeExpensed, ts}.ins[] = {desc, vazn, ayar}— اقلام ورودی. شمارنده درstate.counters.melt.- وضعیت فقط دو مقدار:
MELT_OPEN='در ذوب'وMELT_DONE='برگشته'. - محاسبات همه بر پایهٔ معادل۷۵۰ و همگی از
kBase()(=settings.karatBase) میآیند:meltIn750= Σ(vazn × ayar ÷ base) ·meltOut750=outWeight × outKarat ÷ base·meltDiff= خروجی − ورودی (فقط برای قبضِ برگشته، وگرنه صفر) ·meltPct=diff ÷ in750 × 100. - عیارِ خالی در هر ردیف به
kBase()برمیگردد، پس ردیفِ ناقص محاسبه را صفر نمیکند. meltAddToInv(m)یک ردیف درstate.inv.meltsباmeltIdمیسازد؛meltFeeExpense(m)یک رکورد درstate.expensesبا همانmeltId. هر دو با پرچم (invAdded/feeExpensed) idempotent هستند.meltUnlink(m)هنگام حذف، فقط رکوردهایی را پاک میکند کهmeltId === m.idدارند؛ رکوردهای دستیِ کاربر دستنخورده میمانند.meltReceiptHtml(m)از همان کلاسهایmln-*فاکتور وid="docFactorPrint"استفاده میکند تا قانونِ@media printموجود بدون تغییر کار کند.- سازگاری عقبرو:
meltList()وmeltAddToInvآرایههای نبود را lazy میسازند، پس دادهٔ قدیمی (یا بازگردانی از پشتیبانِ قدیمی) خطا نمیدهد. - تست:
node scripts/test-melt.js— توابع واقعی را ازpublic/admin.jsاستخراج و درvmاجرا میکند (بدون مرورگر). ۳۳ بررسی شامل ریاضیات افت/سرک، idempotent بودن اتصالها، حذف زنجیرهای و escape شدن ورودی در قبض چاپی.
#جریان دیپلوی
سرویس: gold-app.service روی /home/ubuntu/gold-app، اجرا با کاربر ubuntu روی پورت ۸۰.
- ویرایش فایلها در
public/(و در صورت لزومserver/server.js). - صحتسنجی محلی:
node --check public/admin.js(وnode --check server/server.js) + همهٔ تستها:test-melt،test-perf،test-abshode-retail،test-fx-coin،test-doc-layout،test-doc-flow،test-stock-flow،test-check-book،test-status-board،test-non-gold-goods،test-stock-adjust،test-server-body،test-repair،test-hedge،test-remit،test-bal،test-return،test-vat-exempt،test-installment. و در پایانnode scripts/lint-refs.jsکه حالا با خروجیِ صفر سبز است؛ پنج موردِ بررسیشده در خودِ اسکریپت با دلیل درACCEPTED_DATA/ACCEPTED_IDثبت شدهاند و «پذیرفتهشده» چاپ میشوند. هر موردِ تازه خروجی را قرمز میکند و باید بررسی شود. اگرdocs/راهنمای-پنل-ادمین.mdعوض شد،node scripts/build-rahnama.jsوnode scripts/check-doc-links.jsهم اجرا شوند.test-abshode-retailوtest-fx-coinسرورِ واقعی را بالا میآورند.db.jsپوشهٔ داده را ازGOLD_DATA_DIRمیخواند و این دو تست آن را روی یک پوشهٔ موقتِ خودپاکشونده میگذارند، پسdata/دستنخورده میماند و اجرای دوبارهشان نتیجه را دوبرابر نمیکند. - افزایش پارامتر کش
?v=در HTMLِ هر پنلی که فایلهایش عوض شده (هم CSS هم JS). اگر تغییر فقط سمتِ یک پنل بوده، همان یکی بالا میرود و نسخهها موقتاً نامساوی میمانند — این درست است و کشِ پنلِ دیگر بیدلیل باطل نمیشود.در تستها توکنِ کش را هاردکد نکن.
test-stock-flowاین کار را کرده بود و همین بالا بردنِ نسخه در v11 شکستش. حالا فقط بررسی میکند که هر دو فایل توکن دارند، توکنشان یکی است و از v10 عقبتر نیست — چیزی که واقعاً اهمیت دارد و با هر انتشارِ بعدی نمیشکند. - قبل از آپلود، جهتِ اختلاف را چک کن. md5 فایل محلی و سروری را مقایسه کن و اگر فرق داشت با
diffببین کدام طرف جلوتر است. فقط فایلی را بفرست که محلی سوپرست آن است.نکتهٔ تاریخی که دیگر برقرار نیست:
public/app.jsوpublic/index.htmlزمانی روی سرور تغییراتِ خارج از مخزن داشتند. در دیپلوی ۱۴۰۵/۰۵/۱۶ هر دو با مخزن یکی بودند و از آن پس مثل بقیهٔ فایلها دیپلوی میشوند. با این حال مرحلهٔ ۴ را هیچوقت رد نکن. - پشتیبانگیری روی سرور با یک برچسبِ زمانیِ مشترک: از هر فایلِ هدف
cp -p <file> <file>.bak-$TSو یکtar czf backups/data-uploads-$TS.tar.gz data public/uploads. برچسبِ مشترک باعث میشود برگرداندنِ کلِ یک دیپلوی یک دستور باشد.آپلودها روی سرور در
public/uploadsهستند، نهuploads/سطحِ ریشه. - کپی به سرور و صحتسنجی همانجا:
node --check. سپس md5 محلی و سروری را مقایسه کن تا از کاملِ بودنِ انتقال مطمئن شوی. - اگر هر فایلی زیرِ
server/عوض شد (نه فقطserver.js—db.jsهم در همین دسته است):sudo systemctl restart gold-app. فایلهایpublic/ریاستارت نمیخواهند چون استاتیک سرو میشوند.قبل و بعدِ ریاستارت
md5sum data/admin_store.jsonرا بگیر. اگر عوض شده بود یعنی چیزی در بالا آمدن سرویس داده را بازنویسی کرده و باید فوراً ازbackups/برگردانده شود. - بررسی سلامت: کد ۲۰۰ برای
/،/adminو فایلهای نسخهدار؛ سالم بودن/api/admin-storeو/api/admin-backup؛ و بدونتغییر ماندن حجمdata/admin_store.json. برای اطمینان از اینکه واقعاً کدِ تازه سرو میشود، خروجیِcurlرا باgrepروی یکی از نامهای تازه (مثلاًdocFlowHtml) بررسی کن — کدِ ۲۰۰ بهتنهایی یعنی فایل هست، نه اینکه فایلِ جدید است.آزمونِ دسترسی از بیرون ممکن است در محیطِ اجرای agent با timeout رد شود؛ این محدودیتِ خروجیِ همان محیط است نه قطعیِ سرویس. برای تفکیک، همان
curlرا روی خودِ سرور با IP عمومی بزن وss -tlnp | grep :80را ببین. - برای دیدن نسخهٔ جدید، تب مرورگر کاملاً بسته و باز شود.
#وضعیت زندهٔ فعلی
| مورد | مقدار |
|---|---|
| آخرین دیپلوی | ۱۴۰۵/۰۵/۲۱ — برچسب پشتیبان pre-v30-20260812-130851 |
| کشِ پنل ادمین | admin.css و admin.js روی ?v=20260812c |
| کشِ سایت فروشگاه | styles.css و app.js روی ?v=20260807b |
| محتوای این دیپلوی | تاریخچه کارها (v30) — صفحهٔ گزارشِ تازه، موتورِ تفاوتِ فیلدبهفیلد در saveDoc، عکسِ حذفشدهها، و بازنویسیِ logAction روی logEvent |
| فایلهای رفته | public/admin.js، public/admin.css، public/admin.html، public/rahnama.html |
| ریاستارت | لازم نبود — چیزی زیرِ server/ عوض نشد (مرحلهٔ ۷)؛ سرویس از ۱۴۰۵/۰۵/۲۰ بیوقفه active مانده |
| تأییدِ بایتبهبایت | md5 هر چهار فایل روی سرور برابرِ محلی؛ و curl روی IP عمومی برای admin.js همان 76da35a6… را برگرداند — یعنی کدِ تازه واقعاً سرو میشود، نه فقط روی دیسک است |
| دادهٔ فروشگاه | data/admin_store.json قبل و بعدِ آپلود یکسان: fa8f1d3c…، ۴۱۵۱۱۹ بایت |
| سلامت | /، /admin، /rahnama.html، هر دو فایلِ نسخهدار و /api/admin-store همگی ۲۰۰ (هم روی 127.0.0.1 و هم روی IP عمومی)؛ سرویس active، شنونده روی :80، لاگِ ده دقیقهٔ اخیر بدون خطا |
| صحتسنجیِ پیش از انتشار | ۲۵ مجموعهٔ تست همه سبز · node --check محلی و روی سرور · lint-refs.js خروجیِ صفر · ۱۱۷ لینکِ داخلیِ سند سالم (۰ شکسته) |
| کارِ باز | ۱۴ کاراکترِ خرابِ بهجامانده در data/admin_store.json (بانک ملت و دلار) از دورهٔ پیش از v15 هنوز ترمیم نشدهاند. خرابیِ تازه از v15 متوقف شده ولی خرابیِ قدیمی خودبهخود پاک نمیشود |
آمادهٔ دیپلوی، هنوز نرفته: «اجاره طلا» (v31) محلی ساخته و تست شده است —admin.js،admin.css،admin.htmlوrahnama.htmlعوض شدهاند و تگِ کش محلی روی?v=20260812dرفته، ولی روی سرور هنوزcاست. تا وقتی این سطر برداشته نشده، جدولِ بالا وضعیتِ سرور را میگوید نه وضعیتِ مخزن. چیزی زیرِserver/عوض نشده، پس مرحلهٔ ۷ (ریاستارت) لازم نیست.
نامساوی بودنِ 20260812c و 20260807b عمدی است: فایلهای سایت فروشگاه در این دیپلوی دست نخوردند، پس کشِ کاربرانِ آن بیدلیل باطل نشد. مرحلهٔ ۳ را ببین.
بررسیِ جهتِ اختلاف (مرحلهٔ ۴) در این دیپلوی:admin.jsنُه خطِ فقط‑روی‑سرور داشت و هر نُه دقیقاً نسخهٔ پیش‑از‑v30ِ همان سطرهایی بودند که بازنویسی شدند —logActionِ تختِ قدیمی،ALL_VIEWSِ بدونِhistory، سطرِsaveDocبدونِhistLogDocEdit، سه حذفِ بدونِsnap(شخص، کاربر، قبضِ ذوب)، دکمهٔ چاپِ بدونِ ثبتِ رویداد، سرصفحهٔ اتاق فرمانِ بدونِ دکمهٔ تاریخچه، و متنِ کوتاهِ تأییدِ پاکسازیِ لاگ.admin.cssصفر خطِ فقط‑روی‑سرور داشت (کلِ بلاکِ.hs-*الحاقی است) وadmin.htmlفقط دو تگِ?v=20260812b. محلی سوپرستِ سروری بود. نکتهٔ محیطی که دوباره تکرار شد:curlاز داخلِ محیطِ agent به IP عمومی کدِ000میدهد. این محدودیتِ خروجیِ همان محیط است، نه قطعیِ سرویس — همانcurlروی خودِ سرور و به همان IP عمومی، ۲۰۰ برمیگرداند. مرحلهٔ ۸ همین را میگوید و این دیپلوی تأییدش کرد.
دیپلوی پیشین: ۱۴۰۵/۰۵/۲۱ — کشِ ادمین ?v=20260812b، محتوا «دفتر روزانه» (v29) — صفحهٔ مستقلِ برشِ زمانی با پنج کارتِ فیلتر، خطِ جداگانهٔ سود و مالیات، و نشانگذاری با Space؛ ریاستارت نشد.
دیپلوی پیشین: ۱۴۰۵/۰۵/۱۹ — برچسب20260810-100141، کشِ ادمین?v=20260810c، محتوا «سکهٔ پارسیان» (v21) — اجرتِ عددی (اجرت = تعداد × فی)، اجباریشدنِ تعداد، معافیتِ ردیفیِ ارزش افزوده، «وزن یکعدد» و بازشدنِ ستونِ تعداد برای ردیفِ طلا؛ ریاستارت نشد. بررسیِ جهتِ اختلاف در آن دیپلوی:admin.jsبیست خطِ فقط‑روی‑سرور داشت و هر بیست دقیقاً نسخهٔ پیش‑از‑v21ِ همان سطرهایی بودند که بازنویسی شدند — سه خطِwageRial(var perGram = num(wg.fi);و دو خطِ پسِ آن)، پنج خطِdocTaxBreakdown(از جملهvar tax = rnd((wageTot + profit) * vPct / 100);وreturn {…}ِ بدونِexGold)، سطرِ برچسبِ مالیات، سلولِ تعدادِ بیgold، سلولِ مبلغِ بیnovatFlag، پنج خطِwageForm(MODESِ سهتایی، برچسبِ فی،wageOut،display، شنوندهها) و چهار خطِgoodsTypeForm.admin.cssصفر خطِ فقط‑روی‑سرور داشت وadmin.htmlفقط دو تگِ?v=20260810b. محلی سوپرستِ سروری بود.
دیپلوی پیشتر (v20): ۱۴۰۵/۰۵/۱۹ — برچسب20260810-080511، کشِ ادمین?v=20260810b، محتوا «مرجوعی در تکفروشی» (v20) — برگشتِ سود و مالیات با ردیفِ مرجوعی، تاریخِ مستقلِ ردیف، دکمهٔ ↩ و Ctrl+R، و گِردکردنِ متقارنِrnd؛ ریاستارت نشد. در آن دیپلویadmin.jsهفده خطِ فقط‑روی‑سرور داشت که خودِ باگ هم میانشان بود (if (r.kind === 'gold' && r.tashkhis !== 'مرجوع')وif (goldVal <= 0 && wageTot <= 0) return null;).
دیپلوی قدیمیتر (v15): ۱۴۰۵/۰۵/۱۷ — برچسب20260808-183622، کشِ ادمین?v=20260808a، محتوا «باگیابیِ سرور» (v15) — خرابیِ UTF-8 در بدنهٔ درخواست، سقفِ بدنه، ذخیرهٔ اتمی، هشدارِ شکستِ ذخیره، عقبنشینیِ پولِ روبیکا. فایلها:public/admin.js،public/admin.html،server/server.js،server/db.js؛ ریاستارت شد چون دو فایل زیرِserver/عوض شده بودند.data/admin_store.jsonقبل و بعدِ ریاستارت یکسان (57215f1a…، ۴۱۵۱۵۷ بایت). بررسیِ جهتِ اختلاف در آن دیپلوی: هر چهار فایل شمرده شدند و همهٔ خطوطِ فقط-روی-سرور دقیقاً نسخهٔ پیشاز‑fixِ همان سطرهایی بودند که بازنویسی شدند —admin.jsدو خط (var saveTimer = null;وfetch(...).catch(function () {}))،admin.htmlدو خط (همان دو تگِ?v=20260807h)،server.jsپنج خط (سه خطِreadBodyقدیمی،writeFileSyncِ مستقیمِadmin_store.json، وconsole.errorِ بیقیدِ روبیکا) وdb.jsیک خط (writeFileSyncِ مستقیم). محلی سوپرستِ سروری بود.
پیش از آن: ۱۴۰۵/۰۵/۱۷ — برچسب20260808-130243، کشِ ادمین?v=20260807h، محتوا «اصلاح موجودی» — رساندنِ دفتر به عددِ ترازو با سند، نه با پاککردنِ خاموش (v14)؛ ریاستارت نشد چون چیزی زیرِserver/عوض نشده بود. در آن دیپلویadmin.jsنُه خطِ فقط-روی-سرور داشت (سطرِ[data-it]بدونِinvSelClearو چهار سطر از هرکدام ازinvTblMelts/invTblGoods) که همگی نسخهٔ پیشاز‑v14ِ سطرهای بازنویسیشده بودند. نکتهٔ ابزاری: در محیطِ agent دستورdiffیک خلاصهسازِ خوانا است و خطوطِ استانداردِ</>تولید نمیکند، پسdiff | grep -c '^<'جوابِ گمراهکنندهٔ صفر میدهد. برای شمارشِ درست از/usr/bin/diff --old-line-format=… --new-line-format=… --unchanged-line-format=…استفاده کن.
پیش از آن: ۱۴۰۵/۰۵/۱۷ — برچسب20260808-101643، کشِ ادمین?v=20260807f، محتوا «اثر چک بر خلاصه وضعیت» — زیان در برابرِ سربهسر (v12)؛ ریاستارت نشد.
#بازگرداندن یک دیپلوی
با برچسبِ زمانیِ همان دیپلوی ($TS):
cd /home/ubuntu/gold-app
for f in public/admin.js public/admin.css public/admin.html server/db.js server/server.js; do
[ -f "$f.bak-$TS" ] && cp -p "$f.bak-$TS" "$f" # هر دیپلوی فقط فایلهای خودش را پشتیبان گرفته
done
sudo systemctl restart gold-app # فقط اگر چیزی زیر server/ برگشت
داده جداست و با برگرداندنِ کد دست نمیخورد. اگر لازم شد خودِ داده هم برگردد، backups/data-uploads-$TS.tar.gz را باز کن — ولی اول سرویس را متوقف کن تا نوشتنِ همزمان فایل را خراب نکند.
#وام و تسهیلات
- وامها در
state.catalog.loans[]نگهداری میشوند؛ هر وام{id, name, bankName, depositId, depositName, principal, interest, instCount, instAmount, startDate, note}. - هیچ نوع سندِ تازهای اضافه نشده. وام فقط یک مقصدِ حساب جدید است:
bankKind: 'loan'در کنارِbank/amanat/capital— پسdestAcctOptionsوdestAcctNameگروهِ «وام و تسهیلات» را هم میدهند وacctDocDelta('loan', id)ماندهٔ وام را میسازد. - هر سندِ وام دو فیلد اضافه دارد:
loanIdوloanRole ∈ {principal, charge, payment}. سندِ سمتِ بانکloanRole = '<role>-bank'میگیرد و باloanPairIdبه جفتش وصل است. - جهتها (با همان
DIR): دریافت وام → سمتِ وامپرداخت(بدهی +) و سمتِ بانکدریافت؛ سود/کارمزد → فقط سمتِ وامپرداخت؛ قسط → سمتِ وامدریافت(بدهی −) و سمتِ بانکپرداخت(فقط در روش «حواله»). loanDocsOf(id)عمداً فقطbankKind === 'loan'را برمیدارد تا سندهای سمتِ بانک دوباره شمرده نشوند؛loanStatsازMath.abs(docTotals(d).rial)استفاده میکند و تفکیک را ازloanRoleمیگیرد.- ردیفهای سند از نوع
kind: 'rial'باfi = amountساخته میشوند؛ چونdocTaxBreakdownفقط روی سندِ «فروش» باtaxOnکار میکند، مالیات به وام نمیچسبد. - «چک دیگران» از
chkList()فقط چکِ دریافتیِدر جریانرا انتخاب میکند و روی همان ردیفِ سند، وضعیت را بهخرج شدهمیبرد؛outIdبه سند قسط وchkSpendOfبه مرجعdocId#rowIndexوصل میشوند. برگه حذف نمیشود تا زندگینامه و بازگردانی آن سالم بماند؛ بانک/شماره/سررسید نیز درnoteسند نوشته میشود. deleteLoanDocs(loanId)همهٔ سندهای هر دو سمت را باd.loanIdپاک میکند.
#سربرگها و میزِ کار — v23 و v42
showView(view)رندرِ خامِ صفحه است و نامِ صفحهٔ واقعاً نمایشدادهشده را برمیگرداند؛go(view)همان قبلی از دیدِ بقیهٔ کد است ولی سربرگِ فعال را هم بهروز میکند. هیچ صداکنندهٔgo()نیاز به تغییر نداشت.- حالت در
wtabs[] = {id, view, doc}وactiveTabاست. چونRENDER.docهمیشه ازcurDocمیسازد، برای هر سربرگ فقط نگهداشتنِ یکcurDocکافی است —stashActive()قبل از خروج ذخیره وadoptTab()هنگام ورود بازمیگرداند. - نکتهٔ مهم: همگامسازیِ
t.doc = curDocدر ابتدایRENDER.docانجام میشود، نه فقط درgo(). چونsaveDocو دکمهٔ «سند جدید» بعد ازnewDoc()مستقیمRENDER.doc()صدا میزنند؛ بدون این کار، رفتوبرگشتِ بین سربرگها سندِ ذخیرهشدهٔ قبلی را دوباره باز میکرد. commitFocus()قبل از جابهجاییblurمیزند، چون هندلرهای فرمِ سندonchangeهستند و آخرین فیلدِ ویرایششده باید commit شود.closeTabاگر سربرگ سندِ پُر داشته باشد (docHasDataبر پایهٔdocTotals+ وجود طرف حساب)confirmModalمیگیرد؛ بستنِ واقعی درdropTabاست. آخرین سربرگ بسته نمیشود.- پنجرهٔ جدا:
admin.html?view=<name>&win=1. در این حالتwinModeروشن،body.win-modeاضافه و کلاً سربرگ/سایدبار پنهان میشود؛bootبهجایopenTabمستقیمshowViewصدا میزند. - منو:
Ctrl/⌘+کلیکوauxclickباbutton === 1→openTab؛ روی خودِ سربرگauxclick→ بستن وdblclick→openInWindow.onmousedownبرای دکمهٔ وسطpreventDefaultمیکند تا اسکرولِ خودکارِ مرورگر فعال نشود.
#v42 — از «سربرگ» به «میزِ کار»
ویدئوی مرجع با یک قول تمام میشود: «هر زمان که خواستید اون پنجره رو ببندید، هیچ اتفاقی نمیافته، همهٔ اون اسنادِ قبلی باز سرِ جاشون هست.» v23 این قول را در یک نشستِ مرورگر نگه میداشت؛ v42 آن را در برابرِ رفرش، کرشِ مرورگر، صفحهکلید و مانیتور دوم هم نگه میدارد.
- ماندگاری.
tabsSnapshot()یک شیءِ سریالشدنی{v, at, seq, active, tabs:[{id, view, doc, drill}]}میسازد وtabsSave()آن را با ۲۵۰ms دیبانس درlocalStorage[tabsKey()]مینویسد.tabsKey() = 'goldapp_wtabs:' + state.book.id— کلید به دفتر بسته است، پس با سوئیچِ دفتر میزِ کارها قاطیِ هم نمیشوند و همان قفلی کهpersist()باbookLocked()دارد اینجا لازم نمیشود. - تکِ نقطهٔ فراخوانی.
tabsSave()فقط از انتهایrenderTabs()صدا زده میشود. چونRENDER.docدر همان ابتدای خودشrenderTabs()میزند، هر ویرایشِ سند هم خودبهخود ذخیره میشود؛ نیازی نبود ده جای دیگر قلاب بگذاریم.tabsBootedتا پایانِ boot جلوِ نوشتنِ عکسِ نیمساختهٔ روی میزِ واقعی را میگیرد. - اعتبارسنجی جدا از بازگردانی.
tabsUsable(snap)تابعِ خالص است و همهٔ قواعدِ دورانداختن را دارد: عکسِ خالی، عکسِ کهنهتر ازTABS_TTL(یک هفته)، صفحههای ناشناخته (!TITLES[view]) و صفحههایی که کاربر دیگرcanViewنیست، و افتادنِactiveِ گمشده روی آخرین سربرگ.tabsRestore()فقط مصرفکنندهٔ آن است. این جداسازی عمدی است: تمامِ قواعدِ ریسکیِ «چه چیزی حق دارد برگردد» بدون DOM تست میشود. seqهم برمیگردد. اگرtabSeqاز عکس خوانده نشود، سربرگِ بعدی شناسهٔ تکراری (wt1) میگیرد و کلیک روی یکی، دیگری را باز میکند — همان قاطیشدنی که کلِ این قابلیت برای جلوگیری از آن ساخته شده.- boot. ترتیب:
winMode→tabsRestore()→openTab(startView). اگر بازگردانی موفق شد و آدرس صریحاً?view=داشت (urlView)، آن صفحه بهعنوان سربرگِ تازه روی میزِ بازگرداندهشده باز میشود، نه بهجایش. tabDirty(t)جایdocHasDataرا در تصمیمها گرفت:docHasData(d) && !docIsSaved(d). هم.wt-dotرا واقعی کرد (نقطهای که روی هر سربرگِ سند روشن باشد هیچ خبری نمیدهد) و هم پرسشِ بیموردِcloseTabروی سندِ ذخیرهشده را برداشت. پرسشی که همیشه میآید، همان پرسشی است که کاربر یاد میگیرد نخواند.- جدا کردن = جابهجایی، نه تکثیر.
openInWindow(id)سندِ سربرگ را باtabXferPutدر یک کلیدِ یکبارمصرفِgoldapp_tabxfer:<rand>میگذارد و پنجره را با&xfer=<key>باز میکند؛ سمتِ مقصدtabXferTakeآن را برمیدارد و پاک میکند. اگر سربرگ اینجا هم میماند، دو نسخه از یک سندِ نیمهکاره داشتیم و کاربر نمیدانست کدام را ذخیره کند. اگرwindow.openچیزی برنگرداند (pop-up blocker) بُن پس گرفته میشود و هیچ چیز جابهجا نمیشود — شکست نباید داده ببرد. جدا کردنِ تنها سربرگ، آن را بهdashboardبرمیگرداند تا نوار خالی نماند. - پنجرهٔ جدا میزِ کار ندارد، پس تنها محافظش
beforeunloadاست که فقط وقتیdocHasData(curDoc) && !docIsSaved(curDoc)است پرسشِ بومیِ مرورگر را بالا میآورد. - میانبرها با
e.codeخوانده میشوند نهe.key. روی چیدمانِ فارسی حرفِ روی کلیدِ W چیزِ دیگری است و کاربر نباید برای بستنِ سربرگ زبان عوض کند؛ ارقامِ فارسی ('۰۱۲۳۴۵۶۷۸۹'.indexOf) هم بهعنوان fallback خوانده میشوند.tabHotkey(e)خالص است و فقط توصیفِ کار را برمیگرداند ({act:'go'|'cycle'|'close', ...})؛tabHotkeyRun(a)اجرایش میکند و اگر کاری کردtrueمیدهد تاpreventDefaultفقط در همان حالت بیفتد. در RTL «چپ» یعنی جلوتر در نوار، پسAlt+←سربرگِ بعدی است.Ctrl/ShiftهمراهِAltرد میشوند تا با میانبرهای مرورگر تصادف نکنند. moveTab(from, to)باspliceجابهجا میکند و در برابرِ نمایهٔ بیرونِ بازهfalseمیدهد؛ سیمکشیاش HTML5 drag رویِ خودِ.wtabاست (ondragstart/over/drop) با کلاسِ.dropبهعنوان بازخوردِ بصری.tabsMenu(force)فهرستِ کشوی همهٔ صفحههای باز است با شمارهٔ میانبرِ هر کدام و نقطهٔ ذخیرهنشده؛ چیپِ#wtabsMoreفقط از دو سربرگ به بالا دیده میشود. بستهشدنش با یک شنوندهٔ کلیکِ سراسری است کهclosest('#wtabsMenu, #wtabsMore')را استثنا میکند.- تست:
node scripts/test-tabs.js— ۱۲۷ بررسی در ۱۰ بخش. ستون فقراتش رفتاری است نه ساختاری: سندِ سیگرمیِ رضایی بعد از باز کردنِ سربرگِ کریمی،flushروی localStorage، پاک کردنِ کاملِ حالت (شبیهسازیِ F5) وtabsRestore()باید همان وزنِ ۳۰ را برگرداند؛ و جدا کردنِ سربرگ باید سند را از اینطرف بردارد و در بُنِ تحویل بگذارد.
#عیار شخصی و تبدیل متفرقه به ویترین
- ردیف یک فیلد اختیاریِ
ayarCalcگرفت. بدون migration: خالی بودنش یعنی خاموش، چون:rowKaratPhys(r) = num(r.ayar) || karatBase·rowKaratCalc(r) = num(r.ayarCalc) || rowKaratPhys(r). rowW750(r)حالا با عیارِ محاسبه حساب میکند (تکِ تغییرِ رفتاری) وrowW750Phys(r)با عیارِ فیزیکی. چون همهٔ محاسبات مالیِ سند (computeRowMag،wageRial،docTaxBreakdown،rowProfit) ازrowW750میآیند، اثرِ ریالیِ عیار شخصی خودبهخود همهجا اعمال شد و جای دیگری دست نخورد.rowKaratGain(r) = rowW750 − rowW750Phys(فقطkind === 'gold').docKaratGain(d) = Σ −rowMult(d,r) × rowKaratGain(r). علامتِ منفی عمدی است: سودِ مغازه عکسِ اثرِ ردیف روی ماندهٔ طرف حساب است — در فروش سود، در خرید زیان، ومرجوعخودبهخود برعکس میشود چون ازrowMultمیآید.- گزارش سود و زیان:
goldNet = buyGold − sellGold + karatGain. چونdocTotalsبا عیارِ محاسبه است، طلای فیزیکیِ باقیمانده دقیقاً بهاندازهٔkaratGainبیشتر است. تستِ/tmp/karattest.jsهمین اتحاد را اثبات میکند. - فاکتور چاپی ستونِ عیار را با
rowKaratCalc(r)نشان میدهد تا با وزنِ معادل۷۵۰ همان ردیف بخواند؛ عیارِ فیزیکی داخلی میماند. meltToShowcaseForm(preId)مودالِ تبدیل است. چونstate.invدستی است و اسناد آن را تغییر نمیدهند، خودِ تابع هر دو سرِ تبدیل را جابهجا میکند: کمکردنweightاز ردیفِstate.inv.melts(حذفِ ردیف اگر به صفر رسید) وpushبهstate.inv.goodsباgenBarcode()و فیلدهای ردیابیِfromMelt/fromKarat.- سندِ تبدیل مستقیم به
state.docspush میشود (مثلmkLoanDoc) نه از راهsaveDoc، چونpersonId/bankIdندارد. نوعشسایراست پسDIR = 0و جهت کاملاً ازtashkhisردیفها (خروج/ورود) میآید؛fiخالی است پس اثرِ ریالی ندارد. فیلدهای اضافه:convRole: 'meltToShowcase'وconvBarcode. - شرحِ ردیفها از
SHARH_CODESموجود میآید:2(متفرقه) برای خروج و10(متفرقه سالم) برای ورود — کدِ ۱۰ از قبل تعریف شده بود. - سود دوباره شمرده نمیشود: جنسِ تبدیلشده با
karat = 750در انبار مینشیند، پسdocResolveGoodsسرِ فروشr.ayar = 750میگذارد وayarCalcخالی میماند →rowKaratGain = 0.
#کارکرد معاملات (v6)
- باگِ واحد که اصلاح شد:
rowProfit()مقدارِ ریالیِr.fiرا باgram18Price()که تومان است مقایسه میکرد — خطای ۱۰ برابری. حالاmarketRial() = gram18Price() × 10تنها مبنای مقایسه است وshopStatus()هم از همان استفاده میکند تا دو گزارش هممبنا بمانند. PERF_BUCKETSچهار دسته را با کدِSHARH_CODESتعریف میکند:melt(۱،۳) ·misc(۲،۱۰) ·goods(بقیهٔ طلا) ·coin.perfBucketOf(r)ردیفهای غیرطلا/غیرسکه راnullمیدهد تا جریانِ نقدی وارد کارکرد نشود.rowDayProfit(d, r, market)هستهٔ محاسبه است:−rowMult(d,r) × (وزن۷۵۰ × (فی − نرخ روز)) + (−rowMult) × wageRial(r). چون علامت ازrowMultمیآید،مرجوعبدون کدِ اضافه برعکس میشود.coinDayRial(name, market)ارزش روزِ سکه را ازstate.catalog.coinTypesمیگیرد (unitWeight × karat ÷ 750 × market) — همان مبنایی کهphysInventoryبهکار میبرد. نوعِ تعریفنشده ارزشگذاری نمیشود و درunpricedشمرده و به کاربر گزارش میشود؛ عمداً صفرِ خاموش نیست.perfReport(period)علاوه بر گروهها، «اقلام دیگر» را جمع میکند:docKaratGain(سود عیار شخصی، به گرم و ریال)،docTaxBreakdown(سود فروشنده و مالیات)، ردیفهایkind:'discount'، ردیفهای «اضافه» (isAddRow، v31)،docDeltaاسنادِ «سایر» وexpensesTotal(period)با علامتِ منفی. خروجی{market, hasPrice, groups, others, unpriced, tradeNet, othersRial, totalRial, totalGold}.perfReconcileHtml(P, period)فقط درperiod === 'all'مقایسهٔ واقعی میکند؛ معیارِ تراز اختلافِ زیر یک گرم۷۵۰ است. چونstate.invدستی است، تطبیقِ کامل تضمینشده نیست — بهجای پنهانکردنِ اختلاف، دلایلِ محتمل فهرست میشود.- UI:
.perf-cardبا برچسبِ زبانهایِ طلایی (.perf-tab)، جمعبندیِ سهستونه (.perf-total) و جعبهٔ تطبیق (.rec-ok/.rec-warn/.rec-info). راهنمای فرمول باfx(txt, inner)ساخته میشود که فقط یکdata-fxمیگذارد و tooltip کاملاً CSS است (.fx::after) — بدون JS و بدون گرهی اضافه. - تست:
node scripts/test-perf.js— ۴۳ بررسی؛ شامل اعدادِ واقعیِ ویدئوی مرجع (فروش ۲۳۲٫۶۹ گرم و خرید ۸۱۲٫۴۴ گرم)، علامتِ جهت و مرجوع، اجرت بهعنوان سودِ خالص، دستهبندی، ارزشگذاری سکه، تجمیع، سود عیار شخصی، اثرِ هزینه و بیاثر بودنِ برداشت شخصی، و اصلاحِ واحدِrowProfit.
#کارکرد ارز و سکه — سایت فروشگاه (v7)
این قابلیت درpublic/app.js+public/index.html+server/calc.js+server/server.jsاست، نه در پنل ادمین. با «کارکرد معاملات (v6)» که بالاتر توضیح داده شد فرق دارد: آن یکی رویstateسمتِ مرورگرِ ادمین کار میکند، این یکی روی دیتابیسِ سرور.
- کاتالوگ ثابتِ
FX_COIN_CATALOGدرserver/calc.js: شش سکه (باgramوkaratبرای تبدیل) و پنج ارز. کلیدهاcoin:<نام>وfx:<نام>از راهِfxCoinKey(category, name)ساخته میشوند (sekke→coin، بقیه→fx). fxCoinAsset(key)برای کلیدِ خارج از کاتالوگ هم یک تعریفِ حداقلی میسازد، پس نوعِ ناشناخته گزارش را نمیشکند.calcFxCoinLine({side, qty, avgPrice, dayPrice})هستهٔ تکردیف است:unitDiff = فروش ? avg−day : day−avgوprofit = unitDiff × qty. آرایهٔstepsزنجیرهٔ محاسبه را برای پنلِ «این عدد از کجا آمد؟» برمیگرداند — UI فرمول را دوباره نمینویسد، فقطstepsرا رندر میکند تا نمایش و محاسبه از هم واگرا نشوند.calcFxCoinPerformance({trades, dayPrices, gram750Price})بر اساسside|keyگروه میکند؛avgPriceمیانگینِ وزنیِ تعداد است (gross/qty)، نه میانگین ساده.stockجداگانهbuyQty/sellQtyرا برای «موجودی باز» نگه میدارد. مرتبسازی: فروشها اول، بعدMath.abs(profit)نزولی.- دارایی بدون قیمت روز صفر نمیشود:
priced: falseمیگیرد،profitصفر میماند ولی برچسبش درunpriced[]برمیگردد تا UI هشدار بدهد. عمداً عددِ نادرست تولید نمیشود. - مسیرها (همه با
requirePerm('reports')):GET /api/day-prices— کاتالوگ + دفترچهٔ قیمت +updatedAt.POST /api/day-prices— فقط کلیدهای داخلallowed(کاتالوگ +gold:gram750) پذیرفته میشوند؛ مقدارِ ≤۰ کلید را حذف میکند نه صفر بگذارد. درsettings.dayPricesمینشیند باdayPricesUpdatedAtو یک رکوردauth.log.GET /api/reports/fx-coin-performance?from&to— سه بارbuild()صدا میزند:range(داخل بازه)،prior(date < from) وcumulative(date <= to). خروجیattributionهمین سه را میدهد تا اتحادِprior + range = cumulativeسمتِ UI قابلِ نمایش باشد.
- تست:
node scripts/test-fx-coin.js— ۸۹ بررسی؛ شامل تطبیق با جدول مرجعِ ویدئو (نرخ روزِ دلار ۳۵۹۳۰۰ و درهم ۹۷۹۰۲٫۰۶)، جمعپذیری سهم بازهها، میانگین وزنی، ادغام دو خریدِ همدارایی، بیاثر بودنِ فروش طلا در این گزارش، رفتارِunpricedو ۴۰۱ بودنِ مسیرها بدون توکن.
#قالب سند چاپی (v7)
- یک اسکلت، دو مصرفکننده:
docFactorHtml(d)وmeltReceiptHtml(m)هر دو ساختارmln-head→mln-address→mln-box→mln-footرا میسازند و همانid="docFactorPrint"را نگه میدارند، پس قانونِ@media printموجود دست نخورد. - کلاسهای قالب:
.mln-head(گرید1fr 1.1fr 1frبا-r/-c/-l) ·.mln-codeو.mln-noteخطچین ·.mln-boxکادرِ ۲px باborder-radius:14pxوoverflow:hidden·.mln-bandنوارِ نام و کد ·.mln-tableباtr.mln-fillبرای ارتفاع ثابت ·.mln-sum-wrap(فلکس: ریز مالیات چپ، جمعبندی راست) ·.mln-sum-tblسهستونهٔlbl|gram|rial·.mln-footگرید1fr 1fr 1.2fr. - کلاسهای منسوخ
mln-title،mln-meta،mln-summary،mln-typeوsum-mainحذف شدند — هم از HTML هم از هر دو CSS. تست جلوی برگشتشان را میگیرد. - اعداد چاپی جدا از اعداد رابط کاربری:
faMoney/faWt/faCodeفقط,و.خروجیِmoney/wtرا به٬و٫تبدیل میکنند.money/wtعمداً دست نخوردند، چونnum()فقط,را حذف میکند و تغییرِ سراسری، رفتوبرگشتِ عددیِ ورودیهای از پیش پُرشده را میشکست.faCodeجداکننده را فقط روی کدِ کاملاً عددی میگذارد. - خانههای مانده:
balRial(v)،balGram(v, settleKarat, unsigned)(باgoldAtKarat) وbalCoins(coins, keepZero)که هر نوع سکه را در یک<i>میدهد. آستانهها|v|<1ریال و|g|<0.0005گرماند تا خطای ممیز شناور علامتِ بیمعنی نسازد. - باگِ اصلاحشده در
docFactorHtml:after.coinsقبلاً همان ارجاعِbefore.coinsبود، پس اثرِ سکهایِ خودِ سند روی «مانده نهایی» اعمال نمیشد. حالا کپیِbefore.coinsگرفته وdocDelta(d).coinsروی آن جمع میشود. - سمتِ سایت فروشگاه (
public/app.js):showInvoiceوwindow.__showبهasyncتبدیل شدند وinvoiceBalances(inv)ماندهها را از/api/customer/:id/statementو/api/customer/:id/gold-statementمیگیرد و ردیفِ متناظرِinv.numberرا پیدا میکند (i-1= قبلی،i= نهایی). خطا یا نبودِ دسترسی → خانههای خالی، نه صفر. دفترِ سکهایِ هر مشتری در مدلِ سرور وجود ندارد، پس آنجا فقط سطرِ سکهایِ خودِ سند چاپ میشود. - قرارداد علامت در دو پنل یکی نیست و عمداً هم نیست: در
app.jsمثبت = بدهکار (mlnRial/mlnGram)، درadmin.jsمثبتِ ریال و طلا = بستانکار و مثبتِ تعداد سکه = بدهکار. هرکدام با دادهٔ همان پنل میخواند. - تست:
node scripts/test-doc-layout.js— ۶۶ بررسی، بدون مرورگر. توابع واقعیِ هر دو پنل درvmاجرا میشوند و خروجی HTML با سندِ نمونهٔ واقعی تطبیق داده میشود (مانده قبلیبس ۱٬۷۴۴٬۴۵۲٬۹۷۹+بد ۱ ربع، بد ۱ نیم→ فروش یک ربع به ۵۱۲٬۰۰۰٬۰۰۰ → مانده نهاییبس ۱٬۲۳۲٬۴۵۲٬۹۷۹+۰ ربع، بد ۱ نیم). ضمناً بررسی میکند هر کلاسِmln-*که HTML میسازد در CSS تعریف شده باشد و کلاس مرده باقی نمانده باشد.- نکتهٔ استخراج:
admin.jsداخلِ برشِ helpers دوبارهvar stateتعریف میکند، پس مقداردهیِstate.settingsباید بعد ازvm.runInContextانجام شود. برایapp.jsهم استخراجکننده باید کلیدواژهٔasyncرا نگه دارد وگرنهawaitداخلِ بدنه خطای نحوی میدهد.
- نکتهٔ استخراج:
#ریز ورود و خروج و انتخاب چندردیفی (v9)
- هیچ فیلدِ تازهای در مدلِ سند نیست. پنل روی همان
rowsموجود کار میکند، پس اسناد قدیمی هم بدون migration درست نمایش داده میشوند. rowFlowGroup(r)گروهِ ذاتی را ازkindو کدِsharhدرمیآورد:1|3→abshode،2|10→motefarreghe، طلای بیکد →jens،coin→coin، بقیه (rial/wage/discount) →cash. ترتیبِ نمایش از آرایهٔ ثابتِFLOW_GROUPSمیآید نه از ترتیبِ ردیفها، تا جای کارتها با ویرایش سند نپرد.docFlow(d)جهت را ازrowMult(d, r)میگیرد — همان تابعی که ماندهٔ حساب را میسازد. مثبت = ورود، منفی = خروج، صفر (سندِ «سایر» بدونِ تشخیص) = نادیده. مقادیر ازcomputeRowMagمیآیند، پس هر دو سمت مثبت انباشته میشوند و علامت فقط در ردیفِ «خالص» ظاهر میشود.- سود فروشنده و مالیات (
docTaxBreakdown) همجهتِDIR[d.type]روی یک سمت مینشیند؛ برای فروش یعنی سمتِ خروج. به همین دلیلflow.out.rialدر سندِ مالیاتیِ ساده دقیقاً برابرِdocTotals(d).rialدرمیآید. - اتحادِ نگهداشتنی:
docFlow(d).net.w750 === docDelta(d).goldوdocFlow(d).net.rial === docDelta(d).rial. پنل هیچ محاسبهٔ موازیای ندارد و اگر روزی موتورِ جهت عوض شود، تست همینجا میشکند. docFlowHtml(d, mode)تابعِ خالص است (فقط رشته میدهد) و عمداً بالای بخشِ رندر گذاشته شده تا تست بدونِ DOM اجرایش کند. ستونهایاجرت،سکهوسود و مالیاتفقط وقتی میآیند که مقدار داشته باشند؛وزن،وزن ۷۵۰ومبلغهمیشه هستند. خانهٔ صفر رشتهٔ خالی میشود.- اعدادِ پنل با
wt/money(جداکنندهٔ لاتین) نوشته میشوند نهfaWt/faMoney— چون همردیفِ.df-totalsروی صفحهاند؛fa*مخصوصِ سندِ چاپی است. - انتخابِ ردیف در
docSel(آرایهٔ اندیس) وdocSelAnchor(لنگرِ Shift) نگه داشته میشود.syncDocSel()فقط کلاسِrow-selو نوارِ شناور را بهروز میکند و رندرِ دوبارهٔ جدول را لازم ندارد، تا فوکوسِ خانهٔ در حالِ تایپ نپرد.renderDocRowsدر پایان یک بارsyncDocSel()صدا میزند تا انتخاب بعدِ ویرایشِ یک خانه سرِ جایش بماند. - نوارِ
#dSelBarمستقیم بهbodyمیچسبد (نه داخلِ.doc-foot) تا با اسکرولِ صفحه پایین بماند؛z-index: 90زیرِ مودال (۱۰۰) و بالای بقیه است وbottom: 78pxتا روی toast (۲۴px) نیفتد. پاکشدنش سه راه دارد:Escape، حذف/افزودنِ ردیف، وshowView(view !== 'doc'). - کلیکِ انتخاب روی
mousedownبسته شده و اگرe.target.closest('input,select,textarea,button,a,label')باشد زود برمیگردد، پس تایپ و بازکردنِ سلکتها دستنخورده میماند. فقط در حالتِ ShiftpreventDefaultمیشود تا مرورگر متن را هایلایت نکند. - تست:
node scripts/test-doc-flow.js— ۱۰۱ بررسی، بدون مرورگر. سندِ آزمون بازسازیِ همان سندی است که در ویدئوی مرجع دیده میشود و اعدادِ انتظار عیناً از خودِ ویدئو گرفته شدهاند: آبشده ورود۵۸٫۳۴، متفرقه ورود۳۰٫۷۲، جنس خروج۳۰٫۳۷و نشانِ شناورِ۱۹٫۱۸با انتخابِ دو ردیفِ اول. اتحادِ بالا، کاملِ کلاسهای CSS و اتصالهایadmin.jsهم بررسی میشوند.
#گردش موجودی — کاردکس قلم (v10)
- باز هم بدون فیلدِ تازه. کاردکس از همان
state.docs[].rowsساخته میشود؛ هیچ جدولِ موجودیِ موازیای نوشته یا نگهداری نمیشود. یعنی ویرایش یا حذف یک سند بلافاصله در کاردکس دیده میشود و امکانِ ناهمخوانیِ دفتر با اسناد صفر است. - هویتِ قلم
stkKey(group, name, ayar)است: گروهِrowFlowGroup+ نامِdesc+ عیار. عیار عمداً بخشی از کلید است تا «آبشده آسیا ع۷۴۰» با ع۷۵۰ قاطی نشود؛ چندانتخابی جای این محدودیت را میگیرد. سکه عیار ندارد (ayar = 0). stkRowSubj(r)برای گروهِcashو ردیفِ بینامnullمیدهد — نقد، اجرت و تخفیف موجودیِ قلمی ندارند.stkSubjects()کاتالوگ را از دو منبع میسازد: ردیفهای اسناد (moves++) وstate.inv.{goods,melts,bankCoins}(inStock = true). پس قلمی که فقط در انبار خوابیده هم قابلِ انتخاب است. برچسبهای جستوجو (tags) بارکد، نامِ ریگیری و شمارهٔ قبض را میگیرند وstkMatchرویnormSearchکار میکند.- جهت از
rowMult(d, r)میآید، دقیقاً مثلdocFlow. مرجوعی، تشخیصهای مطلقِ سندِ «سایر» و ردیفِ بیاثر (mm === 0) بدونِ یک خطِ کدِ اضافه درست میافتند. - وزنِ ۷۵۰ اینجا
rowW750Physاست، نهrowW750. موجودیِ فیزیکی نباید با «عیار شخصی» تکان بخورد؛ آن اختلاف سودِ حساب است نه طلای جابهجاشده. این تنها جایی است که عمداً ازrowW750استفاده نمیشود. - تاریخها رشتهای مقایسه میشوند، پس
jNormاول یکسانسازیشان میکند (۱۴۰۲/۱/۵→1402/01/05). بدون این کار'1401/6/5' < '1401/05/11'میشد و مرتبسازی بههم میریخت. stkLedger(keys, {from, to})هستهٔ کار است. حرکتِ پیش ازfromحذف نمیشود؛ درopenتا میشود. مرتبسازی چهارسطحی است (date,ts,code,ri) تا ترتیب پایدار بماند. اتحادِ نگهداشتنی:close = open + in − outدر هر بازهای.stkOnHand(keys)طرفِ دیگرِ مقایسه است: جمعِ دستیِ همان کلیدها ازstate.inv.foundجداست ازvazn === 0، چون «ثبت نشده» با «صفر است» فرق دارد و خانهٔ ترازو در حالت اول خالی میماند.stkSuspects(led, diff, field)کارِ کارآگاهیِ ویدئو را خودکار میکند. منطقش یک خط است: حرکتِ مشکوک همسو با نشانهٔ اختلاف است —diff > 0(انبار بیشتر) → متهم سمتِout؛diff < 0(دفتر بیشتر) → سمتِin. دو نوع اتهام:dup(کلیدِside|date|key|valueتکراری) وexact(اندازه برابرِ اختلاف با تلورانسِmax(eps, |diff| × 0.002)).dupاول مرتب میشود و سقفِ فهرست ۶ تاست.stkTableHtml(led, opt)مثلdocFlowHtmlتابعِ خالص است و بالای بخشِ رندر نشسته تا بدونِ DOM تست شود. ستونهای تعداد فقط وقتی میآیند کهtedadدر جریان باشد؛ ستونهای وزن وقتی حذف میشوند که قلم فقط تعدادی باشد (سکه).- حالت در متغیرهای ماژول است (
stkSel,stkPreset,stkFrom/To,stkQ,stkGroup,stkReal) و هر تعامل یکRENDER.flow()کاملِ دوباره میزند. صفحه فرمِ در حالِ تایپ ندارد، پس رندرِ کامل ارزانتر از همگامسازیِ نقطهای است. تنها استثنا#kxRealاست که فیلدِ هدفش را درdata-fحمل میکند تاstkBindمجبور نشود کاردکس را دوباره بسازد. - ورودیهای تازه:
data-kxjumpروی هر ردیفِinvTblGoodsوinvTblMelts(کلیدِ قلم را مستقیم میفرستد)، وdata-kxdocروی ردیفهای جدول و دکمههای متهم که باstkOpenDoc(id)سند را در صفحهٔ سند باز میکند. - تست:
node scripts/test-stock-flow.js— ۱۵۴ بررسی، بدون مرورگر. کاردکسِ آزمون عیناً همان کاردکسِ ویدئوی مرجع است (قلم «سرویس تیغانی»، سال ۱۴۰۱) با ماندهٔ گامبهگام۴۸٫۹۵ → ۲۲۹٫۵۹ → ۲۰۸٫۲۱ → ۴۶۲٫۵۹ → ۵۲۰٫۵۸ → ۸۳۱٫۸۲. اتحادِclose = open + in − out، تاشدنِ ماندهٔ ابتدای دوره، بیاثر بودنِ عیار شخصی، کشفِ سندِ تکراری و سندِ هماندازهٔ اختلاف، و کاملِ کلاسهای CSS و اتصالها بررسی میشوند.
#دفتر چک — چک شخصی و دریافتی (v11)
- سومین قابلیتِ پشتسرهم بدون جدولِ موازی. چک یک شیءِ مستقل نیست؛ یک ردیفِ ریالیِ سند با
sharh === '6'است که مشخصاتش درr.chk = { kind, due, no, bank, bankId, status, settledId, settledDate }مینشیند.isChkRow(r)تنها شرطِ عضویت است. - مبلغ عمداً در
r.chkنیست و همانr.fiمیماند. اگر مبلغِ چک فیلدِ جدا داشت، دو عددِ قابلِ واگرایی میداشتیم (یکی در جمعِ سند، یکی در دفتر چک). این تصمیم تنها دلیلی است که دفتر چک هیچوقت نمیتواند با اسناد ناهمخوان شود. chkKindOf(d, r)نوع را ازrowMult(d, r)میگیرد، نه ازd.type. یعنی مرجوعیِ پرداخت خودبهخود «دریافتی» میشود و سندِ «سایر» با تشخیصِ مطلق هم درست میافتد — همان الگویی کهdocFlowوstkLedgerاستفاده میکنند.r.chk.kindِ صریح همیشه مقدم است.jDay(s)تاریخ جلالی را به شمارهٔ روزِ مطلق تبدیل میکند (ماههای ۱–۶ سیویکروزه، ۷–۱۲ سیروزه). فقط برای اختلاف به کار میرود، پس کافی است با خودش سازگار باشد و لازم نیست باtoJalaliگره بخورد. جایگزینِdaysToJalaliِ قدیمی شد که سال را ۳۶۵ روزِ ثابت میگرفت و سرِ کبیسه یک روز خطا میداد.- راسگیری
chkTotals(list, today).raas=round(Σ(amount × dueDays) / Σ amount). میانگینِ وزنیِ سررسید بر حسبِ مبلغ. روی دادهٔ ویدئوی مرجع دقیقاً همان «راس ۳۳ روز»ی درمیآید که در پاورقیِ کیمیا دیده میشود — که اعتبارسنجیِ مستقلِ فرمول است. - مهلتِ هشدار متناسب با مبلغ است:
chkLeadDays(amount, cfg) = max(days, ceil(amount / unit) × days). تنظیم درstate.settings.chkAlertDaysوchkAlertUnit(پیشفرضِ امن ۳ روز به ازای هر ۵۰۰٬۰۰۰٬۰۰۰ ﷼؛ مقدارِ نامعتبر به همین برمیگردد).chkAlertsفقط چکِدر جریانرا میبیند و سررسیدگذشته را همیشه نگه میدارد. - بازهها (
CHK_RANGES) برخلافِSTK_PRESETSرو به آیندهاند و باjBack(-n)ساخته میشوند.chkRange('late')فقط سقف دارد (to = jBack(1)). - توابعِ خالص (
isChkRow,chkKindOf,chkTitle,jDay,chkDueDays,chkRange,chkList,chkFilter,chkTotals,chkSettings,chkLeadDays,chkAlerts) همه بالای مرزِshowDocFactorنشستهاند تا در همان برشِ تستِ v9/v10 قابلِ استخراج باشند. - پاس کردن دو سند دارد، نه یکی. سندِ اولیه حسابِ طرف حساب را میبندد؛
chkSettle(e, dt)سندِ دومی رویbankKind: 'bank'و همانbankIdمیسازد که موجودیِ بانک را در تاریخ سررسید کم میکند.chkSettleOf = docId + '#' + riردِ اتصال را نگه میدارد وchkUnsettleاز رویsettledIdسند را برمیدارد. حفاظِ دوبارهشماری: اگرe.srcBankId === ba.idباشد سندِ دوم ساخته نمیشود. chkShortfall(e)ازbankLivePrimaryتغذیه میشود و فقط اطلاع میدهد؛ کم بودنِ موجودی جلوی ثبت را نمیگیرد. بانکِ متنیِ آزادbankIdندارد وnullبرمیگرداند — که در پنجره صریح اعلام میشود، نه بیصدا رد.state.checks(مجموعهٔ مردهای که هیچوقت نوشته نمیشد) دیگر خوانده نمیشود؛ هشدارهای داشبورد و پاسخِ دستیار بهchkList()وصل شدند وview: 'checks'ِ شکسته بهcheckbookاصلاح شد.- تست:
node scripts/test-check-book.js— ۱۸۰ بررسی، بدون مرورگر. دفترِ آزمون عیناً همان دفترِ ویدئوی مرجع است (حسابِ «ملت جام»، خرداد ۱۴۰۲) با جمعِ۸٬۶۰۰٬۰۰۰٬۰۰۰و راسِ۳۳. حساب روزِ جلالی سرِ مرزِ ماه و سال، تناسبِ مهلت با مبلغ، جداییِ شخصی از دریافتی، خارجشدنِ چکِ پاسشده و برگشتی از هشدار، و کاملِ کلاسهای CSS و اتصالها بررسی میشوند.
#اثر چک بر خلاصه وضعیت (v12)
- باگی که این نسخه بست: بعد از v11 چکِ پاسنشده در هیچ ستونی از
shopStatus()شمرده نمیشد. سندِ اولیه حسابِ طرف حساب را تسویه میکرد و تعهدِ خودِ چک روی زمین میماند؛ یعنی خلاصهٔ وضعیت دقیقاً به اندازهٔ مبلغِ چک بهتر از واقعیت بود. حالاchkPositionsدو سطرِ ترازنامهای بهaccRowsاضافه میکند (chk-outدر بدهی،chk-inدر طلب) وaccDebtRial/accRecvRialرا میسازد. - قاعدهٔ زمانی: بدهی از لحظهٔ کشیدنِ چک وجود دارد، نه از سررسید.
chkOpen(list)هر چکی را کهstatus !== 'پاس شده'است باز میداند؛ چکِ پاسشده قبلاً سندِ بانکیِ خودش را ساخته و دوباره شمردنش یعنی دو بار کسر. - عدمتقارنِ عمدیِ برگشتی: چکِ شخصیِ برگشتی همچنان در
oweمیماند (پول را ندادهای)، ولی چکِ دریافتیِ برگشتی ازownبیرون میرود و در سطلِ جداگانهٔbouncedمینشیند — نه دارایی، نه بدهی. ترازِ سادهانگارانه همینجا اشتباه میکند. - تفکیکِ زیان از سربهسر:
chkBackedByAsset(d)= آیا سندِ منشأ حتی یک ردیفِkind !== 'rial'دارد؟ ردیفِ غیرریالی یعنی طلا/کالا وارد شده و چک معادل دارد (سربهسر)؛ سندِ تماماً ریالی یعنی هزینه است و چک زیانِ خالص.chkImpact(list)ریزِ هر چکِ شخصیِ باز را بهترتیبِ مبلغ برمیگرداند وchkImpactTotalsدو جمعِbacked/costرا میسازد. shopStatus()حالاchkPosوchkAllPosرا هم برمیگرداند تاRENDER.summaryبدون فراخوانیِ دوبارهٔchkList()پنلِ.st-chkرا بسازد (چهار کارتِ.stc.bad/.stc.ok/.stc.in/.stc.warn). لینکِ[data-gochk]بهgo('checkbook')وصل است.- توابعِ خالص (
chkOpen,chkPositions,chkBackedByAsset,chkImpact,chkImpactTotals) بلافاصله بعد ازchkAlertsو بالای مرزِshowDocFactorنشستهاند تا در همان برشِ تست قابلِ استخراج باشند. - تبدیل مظنه به گرم ۷۵۰: مظنه قیمتِ یک مثقال (۴٫۶۰۸۳ گرم) طلای عیار ۷۰۵ است، پس
price_gram750 = مظنه / 4.6083 × 750/705 = مظنه / 4.3318. عددِGRAM18_DIVISOR = 4.3318ِ موجود در کد دقیقاً همین است — هیچ ثابتِ تازهای اضافه نشد.marketRial() = gram18Price() * 10. - اعتبارسنجی با دو صحنهٔ ویدئوی مرجع: مظنه ۱۱۱٬۷۵۰٬۰۰۰ + چکِ ۵۰۰ میلیون بدونِ موجودی ←
totalRial = −۵۰۰٬۰۰۰٬۰۰۰وtotalGold = −۱۹٫۳۸. مظنه ۱۱۱٬۸۶۰٬۰۰۰ + ۱۵۰ گرمِ ۷۵۰ آبشده در برابرِ چکِ ۳٬۸۷۳٬۴۴۷٬۰۰۰ ﷼ ←totalRial = ۳٬۴۴۷٬۰۰۰وtotalGold = ۰٫۱۳. هر دو در اولین اجرا درآمدند. - مدلِ جهت دست نخورد.
docDeltaبرای «خرید» طلا و ریال را همعلامت میکند (برخلافِ بد/بسِ کیمیا)؛ اصلاحش در ۹ مجموعهٔ تست موج میانداخت و خارج از دامنهٔ این تغییر بود. در تستها داراییی طرفِ مقابل از راهِ موجودیِ فیزیکی (physInventory) مدل شد. - تست:
node scripts/test-status-board.js— ۷۴ بررسی در ۹ بخش، بدون مرورگر.
#کالای غیرطلایی (v13)
- باگی که این نسخه بست:
goodsTypeFormاز قبل گزینهٔkind: 'کالای غیرطلایی'را داشت ولی هیچکس پاییندست به آن اعتنا نمیکرد.docResolveGoodsمگر برایr.kind === 'gold'برنمیگشت و بعدr.ayar = g.karatمینوشت؛ نتیجه اینکه حلقهٔ پلاتینِ ۳۸ گرمی بهعنوان ۳۸ گرم طلای ۷۵۰ وارد دفتر میشد.physInventoryهم همین نقص را برای جدولِ موجودی داشت. هر دو بسته شد. - نوعِ ردیفِ تازه
goodsدر کنارِgold/rial/coin/wage/discount. تمامِ قاعده در یک شاخه ازcomputeRowMagاست و مهمترین خطش خطی است که نوشته نشده:w750در این شاخه دست نمیخورد و صفر میماند. - توابعِ خالص:
isGoodsRow,goodsPerPiece,goodsQty,goodsAmount,goodsCur,goodsRialFactor,goodsTypeIsNonGold— همه بلافاصله بعد ازBABAT_COMMONو بالای مرزِshowDocFactorتا در برشِ تست بیایند. - مبنای فی:
r.gMode ∈ {'piece','weight'}؛ نبودنش یعنیpiece(کالای غیرطلایی معمولاً دانهای است). منبعِ واحدِ حقیقت در کاتالوگ همان فیلدِ موجودِperPieceFiاست — فیلدِ دومی ساخته نشد تا دو مقدارِ واگرا بهوجود نیاید؛ فقط با یک.segصریح («وزنی (هر گرم)» / «عددی (هر دانه)») بهجای چکباکسِ مبهمِ قبلی نمایش داده میشود. نگاشت:r.gMode = g.perPieceFi ? 'piece' : 'weight'. - ارز عمداً به ریال تبدیل نمیشود.
goodsRialFactorفقطریال/﷼/''→ ۱ وتومان→ ۱۰ میدهد و برای بقیه صفر برمیگرداند، یعنی «این ارز ستونِ خودش را دارد». اگر ۲۶۰۰ دلار را با نرخِ زنده به ریال بریزیم، ماندهٔ ثابتِ طرف حساب با هر تکانِ بازار عوض میشود. مسیرِ ارز:computeRowMag → {cur, curAmt}→docDelta/docTotals → curs{}→applyDelta→balances()[id].curs. تنها جایی که نرخِ زنده بهکار میرودshopStatus()است، چون آنجا سؤال «امروز چقدر میارزد» است نه «چقدر بدهکارم». - همراستاسازیِ دوطرفه:
applyGoodsType(r, g)نوعِ ردیف را با نوعِ کاتالوگ هماهنگ میکند — غیرطلایی ←kind='goods'وayar/ayarCalc/wageپاک؛ طلایی ←kind='gold'وcur/gModeپاک. بدونِ این قدم، ردیفی که یکبار پلاتین شده هرگز دوباره طلا نمیشد. physInventory: خروجیngRial,ngCur{},ngWeight,ngCount,ngRows[]گرفت. تشخیص از راهِfindCat(state.catalog.goodsTypes, r.desc)است، پس قلمِ بیتعریف مثل قبل طلا حساب میشود (سازگاری با دادهٔ قدیمی، بدونِ migration). مثلِ شاخهٔ طلا،amountوweightدر انبار «بهازای هر عدد»اند و درcountضرب میشوند.- رابط: دکمهٔ
[data-ngmode]برای تعویضِ عددی/وزنی،ng-cur-selبرای ارزِ ردیف، ستونِ عیار به «بدون عیار» و ستونِ مبلغ به۰٫۰۰۰ گ+ مبلغِ ارزدار تبدیل میشود؛ ستونِ بیاثر (وزن در حالتِ عددی، تعداد در حالتِ وزنی) با.ng-dimکمرنگ میشود. پاورقیِ سند خطِbal-curو ماندهٔ شخص کارتِ ارزی میگیرد. در خلاصه وضعیت پنلِ.st-ngبا دو کارتِ.stn.val/.stn.goldو جدولِ شش قلمِ گرانتر. - اعتبارسنجی با ویدئوی مرجع:
۲ × ۱۳۰۰ = ۲۶۰۰ دلار،۳۸٫۶۱ × ۱۸٬۰۰۰٬۰۰۰ = ۶۹۴٬۹۸۰٬۰۰۰ ﷼،۱۲٫۶۴ × ۲۰٬۰۰۰٬۰۰۰ = ۲۵۲٬۸۰۰٬۰۰۰ ﷼، و جمعِ طلاییِ سند۴۱٫۱۹ + ۱۷٫۶۸ = ۵۸٫۸۷با وجودِ حضورِ هر سه ردیفِ غیرطلایی. - تست:
node scripts/test-non-gold-goods.js— ۱۰۲ بررسی، بدون مرورگر؛ شامل یک محافظِ جامع که هر ۱۹۲ ترکیبِ ممکنِgMode × وزن × تعداد × ارزرا میسازد و صفر ماندنِw750را تضمین میکند.
#اصلاح موجودی (v14)
- باگی که این نسخه بست: پنل از v10 اختلافِ دفتر با انبار را کشف میکرد (
stkReconHtmlماندهٔ دفتری را در برابرِ شمارشِ واقعی میگذاشت و حتی باstkSuspectsردیفِ متهم را نشان میداد) ولی هیچ راهی برای درست کردنش نداشت.state.inv.goodsجدولِ دستی است؛ کاربر میتوانست بیصدا روی ستونِ وزن بنویسد. آنوقتstkOnHandعوض میشد وstkLedgerنه — و این دو برای همیشه واگرا میماندند بیآنکه طلای گمشده جایی بهعنوان ضرر شناسایی شود. - باز هم بدون جدولِ موازی. اصلاح یک سندِ معمولیِ
state.docsاست باadjRole: 'stockFix'.adjIsDoc(d)تنها شرطِ عضویت است. یعنی کاردکس، ماندهها و گزارشها بدونِ یک خطِ کدِ اضافه اثرش را میبینند. - توابعِ خالص (
adjR3,adjIsDoc,adjRowName,adjRowPct,adjEq,adjSnap,adjSplit,adjPlan,adjDocRows,adjBuildDoc,adjTotals) بلافاصله بعد ازgoodsTypeIsNonGoldو بالای مرزِshowDocFactorنشستهاند تا در همان برشِ تستِ v9–v13 قابلِ استخراج باشند.adjPlanهیچ چیزی را تغییر نمیدهد — فقط میگوید چه اتفاقی قرار است بیفتد؛ به همین دلیل پیشنمایشِ زندهٔ فرم و خودِ اجرا از یک تابع تغذیه میشوند و نمیتوانند واگرا شوند. - معادلِ ۷۵۰ عمداً اجرت را میشمارد:
adjEq(vazn, karat, pct) = vazn × (karat/750) × (1 + pct/100). این تنها راهی است که هر سه نتیجهٔ اقتصادیِ ویدئو دقیق دربیایند: صفر کردنِ بیمقصد = کلِ معادل ضرر؛ انتقال به هماجرت =eqNetدقیقاً صفر؛ انتقال به اجرتِ متفاوت = دقیقاً تفاوتِ اجرت (۱۰۰ گرم از ۱۵٪ به ۱۲٪ →−۳٫۰۰۰). - این عدد به کاردکس نشت نمیکند. اثرِ سند بر مانده و موجودی از راهِ
rowW750و وزنِ فیزیکی میآید؛adjEqNetفقط روی خودِ سند مینشیند و صرفاً گزارشی است. اگر اجرت را از راهِayarCalcتزریق میکردیم، «سود عیار» (rowKaratGain) دروغ میگفت. - اجرت در فیلدِ خودش:
adjPct/adjColl/adjIdروی ردیفِ سند مینشینند، نهwage: {mode:'percent'}. اگر از فیلدِ اجرتِ واقعی استفاده میشد،wageRialمبلغ میساخت و سندی که قرار است هیچ پولی جابهجا نکند بدهی و طلب میساخت.fiهم به همین دلیل عمداً خالی است. adjSplit(dW, dC)لبهٔ ظریفِ ماجراست: یک ردیفِ سند یکtashkhisبیشتر ندارد، پس وقتی وزن و تعداد در دو جهتِ مخالف حرکت میکنند (وزن کم، تعداد زیاد) به دو ردیفِ جدا میشکند تا هیچکدام علامتِ دیگری را نبلعد. حدِ خطاADJ_EPS = 0.0005است.- ترتیبِ
adjApplyقابلِ جابهجایی نیست: اول سند ساخته وpushمیشود، بعدstate.invعوض.adjSnapsعکسِ قبل را حمل میکند؛ اگر انبار زودتر دست میخورد، لغو دیگر نمیدانست به کجا برگردد. adjUndo(docId)حتی اگر کاربر بعداً خودِ ردیفِ انبار را حذف کرده باشد کار میکند: از رویadjSnaps[].nameردیف را دوباره میسازد. چون کدبیس هیچ رابطِ عمومیِ «حذفِ سند» ندارد، دستورِ ویدئو («برو ردیفش را از سند پاک کن») با دکمهٔ صریحِ «لغو» درadjHistHtmlجایگزین شد.- پلِ کشف به اصلاح:
adjRowsForKeys(keys)از کلیدِstkKeyبه ردیفِ انبار میرسد. وقتیstkReconHtmlاختلافی رویfld === 'vazn'میبیند و کلید دقیقاً به یک ردیف میخورد، دکمهٔ#kxFixمیآید وadjFormرا با وزنِ ترازو از پیش پُر باز میکند.adjForm(coll, id, pre)آرگومانِ سومِ اختیاری دارد. invRenderTabحالا$('invPanel')نبودن را تحمل میکند و مسیرهای اصلاح بهجای آنrerenderActive()صدا میزنند، چون همان فرم از صفحهٔ «گردش موجودی» هم باز میشود.- رابط: ستونِ
.selcolباdata-adjselدر ابتدایinvTblGoods(۹→۱۰ ستون) وinvTblMelts(۷→۸ ستون)،#adjSelAll، دکمهٔ مدادِdata-adjoneدر انتهای هر سطر،adjBarHtmlبالای جدول (#adjZero,#adjCancel) وadjHistHtmlزیرِ آن (data-adjundo). در خلاصه وضعیت کارتِ.stnبا خروجیِadjTotals(state.docs). - اعتبارسنجی با ویدئوی مرجع: کارتیهِ
۱۴۳٫۶۵گرم با اجرت ۱۲٪ → معادلِ۱۴۳٫۶۵ × ۱٫۱۲ = ۱۶۰٫۸۹ گ۷۵۰— دقیقاً همان عددی که در ویدئو روی صفحه دیده میشود. - تست:
node scripts/test-stock-adjust.js— ۱۴۳ بررسی در ۱۴ بخش، بدون مرورگر؛ شاملِ هر سه سناریوی ویدئو، شکستنِ ردیفِ دوجهته، رفتوبرگشتِ کاملِ لغو (حتی پس از حذفِ ردیف)، و صفر کردنِ دستهجمعی در یک سند.
#باگیابیِ سرور (v15)
این نسخه هیچ قابلیت تازهای اضافه نکرد؛ چهار باگِ واقعی را بست که سهتایشان دادهٔ مغازه را تهدید میکردند.
- خرابیِ خاموشِ متنِ فارسی در بدنهٔ درخواست (بحرانی).
readBodyبدنه را باdata += chunkجمع میکرد. Node هر chunk را جداگانه با UTF-8 دیکد میکند و هر حرف فارسی دو بایت است؛ پس هر حرفی که دقیقاً روی مرزِ دو chunk نصف میشد بهU+FFFDتبدیل میشد. کلِ دفترِ پنل با یک POST ذخیره میشود (الان ۴۱۵ کیلوبایت)، یعنی هر ذخیره دهها مرزِ chunk داشت. خرابی انباشتی هم بود:U+FFFDسه بایت است، پس در ذخیرهٔ بعدی خودش دوباره میشکست و هر بار طولانیتر میشد. در دادهٔ زندهٔ سرور ۱۴ کاراکترِ خراب پیدا شد:بانک ملت(۱۲ کاراکتر، نشانهٔ چند دور انباشت) ودلار(۲ کاراکتر، یک شکستِ ساده). درمان: بایتها در آرایه جمع میشوند وBuffer.concat(chunks).toString('utf8')یکبار در انتها دیکد میکند. - سقفِ ۲ مگابایتیِ بدنه، دو مشکلِ جدا میساخت. یکم:
/api/admin-attachتا ۸ مگابایت را مجاز اعلام میکرد، ولی ۸ مگابایت بعد از base64 حدود ۱۱ مگابایت میشود؛ پس آن بررسی هرگز اجرا نمیشد و پیوستِ بزرگتر از ~۱٫۵ مگابایت با خطای بیربطِ ۵۰۰ رد میشد. دوم و مهمتر: دفترِ پنل یکجا ذخیره میشود و با رشدِ اسناد بالاخره از ۲ مگابایت رد میشد — از آن لحظه هر ذخیره ۵۰۰ میگرفت. سقف به ۲۴ مگابایت رفت و هنگام عبور، اتصال واقعاًdestroyمیشود (قبلاً Promise رد میشد ولی بایتها همچنان در حافظه انباشته میشدند). - شکستِ ذخیره بیصدا دور ریخته میشد.
persist()درadmin.jsروی fetch یک.catch(function(){})خالی داشت وr.okرا هم نمیدید. یعنی کاربر ساعتها سند میزد، پنل هیچ نمیگفت و همهچیز فقط درlocalStorageهمان مرورگر بود. حالا وضعیت باsaveFailedنگه داشته میشود: اولین شکست یکtoastقرمز میدهد و برگشتنِ ارتباط یکtoastسبز؛ بدونِ اسپم در هر ذخیره. - نوشتنِ غیراتمی. هم
/api/admin-storeو همdb.writeمستقیم روی فایلِ اصلیwriteFileSyncمیزدند؛ قطعِ پروسه وسطِ نوشتن، کلِ دفتر را نصفه و غیرقابلJSON.parseمیگذاشت. حالا اول فایلِ.tmpنوشته و بعدrenameSyncمیشود (rename در همان فایلسیستم اتمی است). - حلقهٔ داغِ پولِ روبیکا.
setInterval(rubikaTick, 4000)نه محافظِ همپوشانی داشت نه عقبنشینی، در حالی که مهلتِ هر درخواست ۱۵ ثانیه است؛ پس در قطعیِ روبیکا تا چهار درخواست همزمان روی هم میافتاد. در لاگِ سرویس یک بازهٔ دوساعته دیده شد که هر ۴ ثانیه یک خطای یکسان ثبت شده بود. حالاbusyاز همپوشانی جلوگیری میکند،skipعقبنشینیِ نمایی تا حدود ۵ دقیقه میدهد، و فقط اولین خطای هر دوره و لحظهٔ برگشتِ ارتباط لاگ میشود. - تست:
node scripts/test-server-body.js— ۱۶ بررسی؛ سرورِ واقعی را روی یکGOLD_DATA_DIRموقت بالا میآورد و بدنهٔ فارسیِ ۵۴۰ کیلوبایتی، پیوستِ ۵ مگابایتی، بدنهٔ بالای سقف (سرور نباید بیفتد) و پنج ذخیرهٔ پیاپی را میآزماید. - ابزارِ کمکی:
node scripts/lint-refs.js— بدون مرورگر و بدون وابستگی؛ سه چیز را میگیرد: تابعِ صداشده ولی تعریفنشده (با خودآزمایی: اگر اسکنر روی فایلی دِسینک شود گزارشِ آن فایل را میاندازد، نه اینکه هشدارِ نادرست بدهد)،data-*ی که رندر میشود ولی هیچجا خوانده نمیشود، و$('id')ای که هیچجا ساخته نمیشود. - دانستهٔ باقیمانده (باگ نیست):
liveStripHtml/renderLiveStripدرadmin.jsکدِ مردهاند — عنصرِ#liveStripهیچجا درadmin.htmlساخته نمیشود و جای آن راrateBoxesHtmlگرفته است. چونrenderLiveStripباif (s)محافظت شده، اثری ندارد و عمداً دستنخورده ماند.
#تعمیرات و آبکاری (v16)
- باگی که این نسخه بست — و اندازهاش.
perfBucketOfهر ردیفِ طلا را واردِ «کارکرد معاملات» میکرد وrowDayProfitآن را به نرخ روز میسنجید. ردیفِ امانتِ تعمیرfiندارد، پس فرمولِ−m × وزن۷۵۰ × (فی − نرخ روز)کلِ ارزشِ جنس را سود یا زیان اعلام میکرد. با پروبِ عددی روی خودِ کدبیس اندازهگیری شد: یک انگشترِ ۶٫۳۸ گرمی در نرخِ ۳۰ میلیون ریال بر گرم۷۵۰، بهتنهایی ۱۹۱٬۴۰۰٬۰۰۰ ریال زیانِ خیالی میساخت و بازگشتش ۱۹۰٬۲۰۰٬۰۰۰ ریال سودِ خیالی. بینِ این دو روز — که در مغازهٔ واقعی چند روز است — گزارشِ سود و زیان به همان اندازه غلط بود. - مهم:
docTotals/docDeltaاز اول درست بودند (ماندهٔ سند دقیقاً۰٫۰۴۰درمیآمد، برابرِ ویدئوی مرجع). فقط سمتِ کارکرد دروغ میگفت. این تفکیک، جهتِ فیکس را تعیین کرد. - کلِ فیکس یک خط است: در ابتدای
perfBucketOf→if (repIsCustody(r)) return null;.nullیعنی ردیف اصلاً واردِ هیچ سطلِ کارکردی نمیشود. اثرِ ردیف بر ماندهٔ تعمیرکار و بر کاردکس دستنخورده میماند، چون آنها ازrowW750/rowMultمیآیند نه ازperfBucketOf. - بدون جدولِ موازی و بدون نوعِ سندِ تازه. کارِ تعمیر یک سندِ معمولیِ
state.docsاز نوعِپرداختاست باrepRole: 'repair'وrepKind ∈ {تعمیر، آبکاری، تغییر سایز، سنگنشانی، لحیم و جوش}.repIsDoc(d)تنها شرطِ عضویت است. - چهار نقشِ ردیف در فیلدِ
rep، همه در یک سند:repنوع ردیف tashkhisمعنی outgold''جنس رفت (بیفی، بیاجرت) backgoldمرجوعجنس برگشت feerial''اجرت — بدهیِ ما settlerialمرجوعپرداختِ اجرت repIsCustody(r)فقطout/backرا میگیرد. ردیفِfeeخودشkind: 'rial'است وperfBucketOfاز قبل ریالی را رد میکرد. - چرا
پرداختو نه نوعِ تازه؟DIR['پرداخت'] = −1، پس ردیفِoutماندهٔ تعمیرکار را بدهکار میکند وbackبامرجوعدقیقاً برعکسش میشود. هیچجای موتورِ جهت دست نخورد؛ همان مدلِ «مرجوع یک ردیف است نه یک نوعِ سند» (بخش ۴) کارِ رفتوبرگشت را رایگان انجام داد. - توابعِ خالص (
repR3,repIsDoc,repIsCustody,repOutRow,repBackRow,repFeeRow,repSettleRow,repBuildDoc,repJob,repJobs,repTotals,repWarnings,repStrayReturns) عمداً بالایrowMultنشستهاند، چونperfBucketOfبهrepIsCustodyوابسته شد و برشِ تست باید هر دو را با هم بردارد. همین وابستگی،scripts/test-perf.jsرا شکست و ناچارrepIsCustodyبه فهرستِFNSِ آن اضافه شد — نمونهٔ خوبی از اینکه چرا تستها از فایلِ واقعی برش میخورند. repJob(d)تنها جایی است که وضعیتِ یک کار محاسبه میشود:outW,backW,goldOut = outW − backW,fee,paid,feeDue,returned,done,days,late. فرم، تابلو، جدول و تست همه از همین یک تابع تغذیه میشوند و نمیتوانند واگرا شوند. حدِ خطاREP_EPS = 0.0005و آستانهٔ دیرکردREP_AGE_WARN = 7روز.- دو نگهبان، هیچکدام مخرب نیستند:
repWarnings(d)داخلِ سند:wageOnCustody(اجرت روی ردیفِ طلا — کهdocDelta.rialرا از−۱٬۵۰۰٬۰۰۰به+۱٬۵۰۰٬۰۰۰برمیگرداند؛ اندازهگیری شد)،fiOnCustody،plainGold.repStrayReturns()بینِ سندها: سندِدریافتبا نامِ همان جنس و همانpersonIdدر حالی که کارِ تعمیرِ بازی وجود دارد و تاریخش بعد از ارسال است. تنها تشخیصِ بینسندی در کدبیس؛ خروجی فقط یک پنلِ هشدار است، چیزی خودکار اصلاح نمیشود.
- رابط:
RENDER.repairبا سه کارتِ آمار، پنلِ هشدارِ سرگردان، چیپهای فیلتر (repFilter ∈ {open, late, done, all}) و جدولِ کارها باdata-repback/data-repfee/data-repset/data-repdoc. سه فرم:repSendForm,repBackForm,repMoneyForm. ثبت درALL_VIEWS،TITLESوadmin.html(#view-repair+ آیتمِ منو). - اعتبارسنجی با ویدئوی مرجع: ۶٫۳۸ رفت، ۶٫۳۴ برگشت، ماندهٔ سند
۰٫۰۴۰— دقیقاً عددِ روی صفحهٔ ویدئو؛ و «سود ۰٫۰۰» که در ویدئو تأکید میشود، حالا در کارکردِ ما هم دقیقاً صفر است. - تست:
node scripts/test-repair.js— ۷۹ بررسی در ۱۰ بخش، بدون مرورگر؛ شاملِ دورهٔ خطرناک (فقط ارسال، بدونِ بازگشت — جایی که باگ بیشترین آسیب را میزد)، هر دو اشتباهِ ویدئو با اثرِ عددیشان، چرخهٔ کاملِ چهارمرحلهای، دیرکرد، عیارِ غیر ۷۵۰، و همزیستی با یک فروشِ واقعی در همان دوره.
#پوشش ریسک (v17)
- باگی که این نسخه بست — و اندازهاش. v16 فقط زیرمجموعهٔ «امانتِ تعمیر» از یک حفرهٔ بزرگتر را وصله کرده بود. حفرهٔ اصلی این بود:
perfBucketOfهر ردیفِ طلا را با نرخ روز مارکتومارکت میکرد، حتی وقتی سند اصلاً معامله نبود. سندِدریافت/پرداختفی ندارد چون قیمتش در سندِ معاملهٔ اصلی بسته شده. با پروبِ عددی روی خودِ کدبیس در نرخِMARKET = 13,291,006ریال بر گرم۷۵۰ اندازهگیری شد:- حوالهٔ طلای ۹۵ گرمی روی سندِ
دریافت→ +۱٬۲۶۲٬۶۴۵٬۵۷۵ ریال سودِ خیالی - تسویهٔ ۴۰ گرمی روی سندِ
پرداخت→ −۵۳۱٬۶۴۰٬۲۴۲ ریال زیانِ خیالی - ثبتِ یک پوشش با
پرداختبهجایفروش→ گزارش از+۱۸٬۶۴۲٬۹۳۵به−۹۸۳٬۳۵۳٬۴۶۳پرید؛ حدودِ یک میلیارد ریال خطا از یک انتخابِ اشتباهِ نوعِ سند.
هر سه حالا دقیقاً صفراند.
- حوالهٔ طلای ۹۵ گرمی روی سندِ
- کلِ فیکس باز هم یک خط است، ولی امضای تابع عوض شد:
perfBucketOf(r, d)و در ابتدایشif (hdgIsSettleDoc(d)) return null;. تنها فراخوانیاش درperfReportبهperfBucketOf(r, d)بهروز شد.repIsCustody(v16) سرِ جایش ماند و حالا حالتِ خاصی از همین قانونِ کلیتر است. - آنچه عمداً دست نخورد:
docKaratGainمسیرِ جداگانهای دارد و سودِ عیارِ تهحساب کاملاً دستنخورده است (تست: تسویهٔ ۱۰۰ گرمِ فیزیکیِ ۷۵۰ با عیارِ محاسباتیِ ۷۴۰ همچنان+۱٫۳۳۳گرم۷۵۰ سود میدهد، در حالی که مارکتومارکتش صفر شده). ماندهٔ حساب، کاردکس و ریز ورود ـ خروج هم ازrowMult/rowW750میآیند، نه ازperfBucketOf. - فرمولِ وضعیتِ باز — بهجای حدس، از پروب استخراج شد:
hdgPosition() = Σ p.openGold + Σ over all gold rows: rowMult(d, r) × rowW750(r)برای خریدِ پوششنشدهٔ ویدئو دقیقاً
36.941و برای جفتِ پوشششده دقیقاً0.000میدهد. تسویه هم در وضعیتِ باز میآید (نه در کارکرد): طلبِ ریالی که به طلای فیزیکی تبدیل شده، ریسکِ قیمتِ تازه است حتی اگر سودِ تازه نباشد. - تعریفِ ریاضیِ پوشش، بهجای تعریفِ شهودی. تستِ اصلی این است: سودِ ریالیِ یک جفتِ پوشششده باید در نرخِ
×۰٫۶،×۱و×۱٫۸یک عدد بدهد. میدهد. همان معامله بدون پوشش، بینِ دو نرخ بیش از2e8ریال جابهجا میشود. یک تستِ جدا هم نشان میدهد گرد کردنِ وزنِ پوشش به میلیگرم (hdgR3) ۰٫۲ میلیگرم باز میگذارد و نوسانِ ناشی از آن زیرِ ۲۰ هزار ریال میماند. - توابعِ خالص (
hdgIsSettleDoc,hdgIsTradeDoc,hdgIsWholesale,hdgR3,hdgRowW,hdgDocW,hdgPosition,hdgRisk,hdgDays,hdgOpenDays,hdgSuggest,hdgMisfiled) پیش ازrowMultنشستهاند — به همان دلیلِ v16:perfBucketOfبهhdgIsSettleDocوابسته شد، پس برشِ تست باید هر دو را با هم بردارد. همین وابستگیtest-perf.jsوtest-repair.jsرا شکست تاhdgIsSettleDocبه فهرستِFNSِ هر دو اضافه شد. دو مورد از ادعاهایtest-repair.jsهم بازنویسی شدند، چون v17 همان سودِ خیالیِ v16 را از ریشه حذف کرده و دیگر قابلِ بازتولید نیست. hdgDays(period)هر تاریخ را یک سطر میکند:{date, retail, whole, settle, net, docs}و از تازه به قدیم مرتب است. طرفِ بازار ازHDG_WHOLESALE = ['همکار/بنکدار', 'ذوبخانه']تشخیص داده میشود.hdgOpenDaysروزهایی را میدهد که|retail| > HDG_EPSو|net| > HDG_EPS— یعنی معاملهٔ تکفروشی بوده و بسته نشده. سندِ فقطریالی اصلاً واردِ روزشمار نمیشود.HDG_EPS = 0.0005گرم۷۵۰.hdgSuggest(row)جهتِ عکس و همان وزن:{type: net > 0 ? 'فروش' : 'خرید', vazn: hdgR3(|net|), date}. روی وضعیتِ خنثیnullمیدهد.hdgOpenCoverسند را باnewDocمیسازد و پیشپر میکند: طرفِ بنکدار،priceUnit: 'mesghal'،sharh: '1'(آبشده)، وزن دقیق — و عمداًfiرا خالی میگذارد. مظنه از بازار میآید نه از دفتر؛ حدس زدنش خطای بیسروصدا میسازد.hdgMisfiled()نگهبانِ بینسندی و غیرمخرب: ردیفِgoldباfi > 0روی سندِدریافت/پرداخت→{doc, row, vazn, fi, should}. سندِ تعمیر (repIsDoc) و ردیفِ امانت (repIsCustody) استثنا شدهاند تا اخطارِ نابهجا ندهد.- رابط:
RENDER.hedgeبا سه کارتِ آمار (وضعیتِ باز / ریسکِ n٪ / روزهای پوششنشده)، چیپهای درصد (hdgPct ∈ {1, 2, 5})، پنلِhdg-warnبرای ثبتهای اشتباه، و روزشمارِ مظنه باdata-hgp/data-hgfix/data-hgdoc. ثبت درALL_VIEWS،TITLESوadmin.html(#view-hedge+ آیتمِ منو). آیکونِ گمشدهٔplusهم که از v16 بیسروصدا<svg>خالی میداد بهICONاضافه شد. - تست:
node scripts/test-hedge.js— ۸۵ بررسی در ۱۲ بخش، بدون مرورگر؛ شاملِ هر دو سناریوی ویدئو با اعدادِ واقعی، آزمونِ ناوردایی نسبت به نرخ، بقای سودِ عیارِ تهحساب، همزیستی با امانتِ تعمیرِ v16، و چهار حالتِ نگهبان.
#حواله (v18)
- چه چیزی جا مانده بود. v17 نیمهٔ اولِ ویدئوی مرجع (پوشش ریسک) را پیاده کرد. نیمهٔ دوم — حوالهٔ طلا و حواله از روی مانده — در کدبیس اصلاً وجود نداشت:
remittanceFormفقط ریال میشناخت. - خسارتِ نبودش، اندازهگیریشده. بدونِ حوالهٔ طلا، کاربر ناچار بود انتقالِ طلا بین دو حساب را با «فروش + خرید» بنویسد. پروبِ عددی روی خودِ کدبیس در نرخِ
MARKET = 13,291,006ریال بر گرم۷۵۰:- حوالهٔ ۹۵ گرمی با خرید/فروش → ±۱٬۲۶۲٬۶۴۵٬۵۷۵ ریال ماندهی ساختگی روی دو حساب.
- همان کار یکطرفه → علاوه بر آن،
hdgPosition() = −۹۵وضعیتِ بازِ ساختگی. - با جفتِ حوالهٔ درست: هر دو صفر،
perfBucketOfهمnull(به لطفِ v17 که تسویه را از کارکرد بیرون برد). یعنی v18 روی فیکسِ v17 سوار است.
- مدلِ خالص (پیش از
remitPeer):RMT_EPS_RIAL = 1ریال،RMT_EPS_GOLD = 0.0005گرم۷۵۰.rmtAsset(d)— دارایی از نوعِ ردیف خوانده میشود (rows[0].kind)، نه از یک فیلدِ جدا. پس اسنادِ حوالهٔ قدیمی بدونِ هیچ migration ریالی میمانند.rmtAmountOf(d)— طلا ازvazn، ریال ازfi.rmtSideFor(bal, asset)—bal > 0 → 'from'،bal < 0 → 'to'، زیرِ eps →null. همان قاعدهٔ «طلبکار مبدأ، بدهکار مقصد» که از رفتارِ واقعیِbalances()استخراج شد، نه از شهود.rmtPrefill(personId, asset)→{side, asset, amount}؛ وزن باhdgR3(میلیگرم)، ریال باMath.round.rmtMkRow(asset, amount, ayar, peerName)— تنها جای ساختِ ردیفِ حواله؛ هر چهار فراخوانیِapply()از همین میگذرد. ردیفِ طلا عمداًfi: ''دارد.rmtIsDocوrmtPrintDescعمداً کنارِfactorRowDescنشستهاند، نه در بلوکِ مدل:test-doc-layout.jsبرشِ متنیِvar DIRتاshowDocFactorرا اجرا میکند و بیرون از آن برش،rmtPrintDesc is not definedمیداد.
remittanceFormدودارایی شد. متغیرِ سرِ فرمassetاست وbaseRialبهbaseBalتبدیل شد.amtTxt/eps/readAmtهر سه ازisGold()میخوانند، پس پیشنمایش، چیپهای تسویه و اعتبارسنجی با یک شرط هر دو حالت را میپوشانند. تعویضِ داراییrm_amtرا پاک میکند.remitFromBalance(personId, asset)— میانبُر:rmtPrefillرا میخواند و بسته بهsideیکی ازfromId/toIdرا پر میکند. ماندهٔ صفرtoastخطا میدهد و فرم باز نمیشود.- رابط: در
RENDER.personsماندهٔ ناصفر یک<button class="bal-remit" data-rmt data-rmta>است.factorRowDesc(r)بهfactorRowDesc(r, d)تغییر کرد تاrmtPrintDescرا صدا بزند؛ تنظیماتِremitHidePeerبا#s_rmtHideذخیره میشود. آیکونِinfoبهICONاضافه شد (همان کلاسِ باگی که v17 باplusداشت: کلیدِ نبوده بیسروصدا<svg>خالی میدهد). - تست:
node scripts/test-remit.js— ۷۹ بررسی در ۱۱ بخش، بدون مرورگر؛ شاملِ عددِ ویدئو (۶۱۷٫۳۲ − ۹۵ = ۵۲۲٫۳۲)، خسارتِ اندازهگیریشدهٔ خرید/فروش، ناوردایی کارکرد و وضعیتِ باز، قاعدهٔ جهت روی مرزِ eps، و همزیستی با پوششِ ریسکِ v17.
#تراز (v19)
- حفرهٔ واقعی، نه یک گزارشِ تازه. v17 دو چیز داشت:
hdgPosition()یک عددِ کلی، وhdgDays()تجمیعِ روزانه. هیچکدام نمیگفتند آن عدد چطور ساخته شد. کاربر نمیتوانست ردِ خالص را از اولین فاکتورِ روز تا این لحظه بگیرد، ستونِ ریالی اصلاً وجود نداشت، و برای دیدنِ عدد باید هر بار به صفحهٔ پوشش ریسک میرفت. v19 هر سه را میبندد و هیچ محاسبهٔ تازهای اختراع نمیکند — روی همانhdgRowWوcomputeRowMagِ تستشدهٔ v17 سوار است. - مدلِ خالص (کنارِ
rowMult، پیش از آن):BAL_EPS = 0.0005گرم۷۵۰.balDocSplit(d)→{buyW, sellW, buyR, sellR}. دستهبندی از جهتِ مؤثرِ ردیف (hdgRowWکه خودشrowMult × rowW750است) میآید، نه ازd.type. این تصمیمِ اصلیِ طراحی است: یک ردیفِمرجوعدر فاکتورِ فروش، یاtashkhis: 'ورود'در سندِ «سایر»، خودبهخود در ستونِ درست مینشیند. پایِ ریالی|computeRowMag(r).rial|است (وزن۷۵۰ × فی + اجرت).balDocs(range)— اسناد از قدیم به جدید (jDay→ts→code)، برعکسِhdgDays. ماندهٔ دونده فقط با این ترتیب معنا دارد.balLedger(range)→{rows, totals}؛ هر سطرnetW/netRتا همان لحظه را حمل میکند. سندِ بیردیفِ طلا اصلاً سطر نمیسازد.balDirWord(net)→'خرید'اگرnet > BAL_EPS،'فروش'اگرnet < −BAL_EPS، وگرنه''. این عکسِhdgSuggest().typeاست و باید باشد: یکی سمتی است که رویش هستی، دیگری کاری که برای بستنش باید بکنی. بخشِ ۱۰ تست دقیقاً نگهبانِ همین است.
- چرا ماندهٔ افتتاحیه در دفتر نیست.
hdgPosition()مجموعِopenGoldرا هم دارد؛balLedgerفقط گردشِ اسناد است. دفتری که سطرِ متناظر ندارد نباید در جمعش عددِ بیسطر داشته باشد. تست هر دو ادعا را همزمان میسنجد: بدونِ افتتاحیه دو عدد یکیاند، با افتتاحیهٔ ۲۰ دقیقاً ۲۰ اختلاف دارند. - نوارِ پایین با DOM ساخته میشود، نه در
admin.html.renderBalBar()عنصرِ#balBarرا در صورتِ نیازappendChildمیکند و با خاموششدنِ هر دو نمایشremove()میکند؛ کلاسِhas-balbarرویbodyجای نوار را باز میکند. دلیلش این است که نوار مشروط است و یک عنصرِ همیشهحاضرِ خالی در شل، همان دِینِ#liveStripِ مرده را تکرار میکرد. - قلابِ بهروزرسانی:
persist()(تنها گلوگاهِ «داده عوض شد») وshowView(). همین باعث شدtest-stock-adjust.jsبشکند — آن تست برشِ متنیِ شاملِpersistرا درvmاجرا میکند؛ با افزودنِ استابِrenderBalBar: () => {}کنارِ استابهای موجودِ همان هارنس حل شد. - راستکلیک روی نوار
balSettingsForm()را باز میکند: همان سه انتخابِ تنظیمات با شناسههایbs_*(در تبِ تنظیماتs_bal*). گزینهها یکجا درBAL_RANGES/BAL_GOLD_OPTS/BAL_RIAL_OPTSو رندرشان درbalOpts()است، ولیidهر<select>عمداً لفظی نوشته شده تاlint-refs.jsبتواند ساختهشدنش را ببیند؛ ساختِidبا الحاقِ رشته اسکنر را کور میکند و در اولین اجرا هم همین را گزارش داد. - تنظیمات:
balRange('today'/'all')،balGold('net'/'off')،balRial('off'/'on') درdefaults.settings.balRange()هر مقدارِ نامعتبر را به'today'برمیگرداند، پس دادهٔ قدیمیِ بدونِ این کلیدها بیmigration کار میکند. - رابط:
balReportHtml()داخلِRENDER.hedge(بینِ پنلِ هشدار و روزشمارِ مظنه)، باdata-balr(چیپِ بازه) وdata-baldoc(سطر → فاکتور).tfootدو سطرِbal-totدارد. آیکونهایchartوcalendarاز پیش درICONبودند — بررسی شد، چون کلیدِ نبوده بیصدا<svg>خالی میدهد (باگِ تکرارشوندهٔ v16/v17/v18). - تست:
node scripts/test-bal.js— ۵۶ بررسی در ۱۱ بخش، بدون مرورگر؛ شاملِ بازسازیِ کاملِ قصهٔ عددیِ ویدئو (۱۷٫۶۴۰ → ۱۲٫۵۳۰ → ۲۶٫۱۲۰ → ۳۳٫۷۶۰ → پولیکردنِ ۴۲٫۳۷۰ → ۸٫۶۱۰ روی خرید → ۱۱۶٫۷۴۰ → ۱۲۳٫۴۹۰ روی فروش)، مرجوعی و تشخیصهای مطلق، ترجمهٔ عیار، بیمبلغبودنِ تسویه، ترتیبِ مستقل از ثبت، فیلترِ بازه، و برابریِ ترازِ «از ابتدا» باhdgPosition().- هفت وزنِ بالا عیناً از جدولِ روی صفحهٔ نرمافزارِ مرجع خوانده شدهاند (پیشتر اعدادی تقریبی جایشان بود). مرجع وزنها را دو رقمِ اعشار نشان میدهد ولی زیرِ آن میلیگرم نگه میدارد، برای همین جمعِ فروشش را ۱۷۰٫۹۸ و ترازش را ۱۲۳٫۵۰ چاپ میکند در حالی که جمعِ همان هفت عددِ نمایشدادهشده ۱۷۰٫۹۷ و ۱۲۳٫۴۹ است. این ۰٫۰۱ رُندِ خودِ مرجع است، نه اختلافِ موتور: هر هفت ماندهٔ دونده موبهمو یکی است.
#مرجوعی در تکفروشی (v20)
- باگِ مالی، نه یک قابلیتِ تازه.
tashkhis: 'مرجوع'از روزِ اول در کدبیس بود وrowMult/rowSignجهت را درست برمیگرداندند. حفره یک خط بود، درdocTaxBreakdown:if (r.kind === 'gold' && r.tashkhis !== 'مرجوع') { ... } // ← ردیفِ مرجوعی نادیده گرفته میشدیعنی طلا و اجرتِ مرجوعی از جمعِ سند کم میشد (کارِ
computeRow)، ولی پایهٔ سود و مالیات دستنخورده میماند. نتیجه: لایهٔ سومِ مبلغ برنمیگشت. - اندازهٔ خسارت، اندازهگیریشده روی اعدادِ واقعیِ ویدئوی مرجع (قیمتِ طلا ۲۵٫۵۰۰٫۰۰۰، سود ۷٪، مالیات ۹٪):
- سندِ فقط‑مرجوعیِ نیمستِ ۱۰٫۳۷ گرمی با اجرتِ ۱۱٪ → پیش از فیکس
−۲۹۳٬۵۲۲٬۸۵۰، پس از فیکس−۳۱۸٬۵۳۶٬۵۵۱. کسری: ۲۵٬۰۱۳٬۷۰۱ ریال روی یک قلم. - مرجوعی در همان فاکتور → پیش از فیکس
۵۰۹٬۰۴۲٬۱۳۵، پس از فیکس۴۸۴٬۰۲۸٬۴۳۵که دقیقاً مبلغِ ردیفِ باقیمانده است. اضافه: ۲۵٬۰۱۳٬۷۰۰ ریال. - بازسازیِ کاملِ سندِ ویدئو (دو فروش + حواله + مرجوعی) →
docTotals().rial = −۳۱۸٬۵۳۶٬۵۵۰، عیناً «ماندهٔ سند» روی صفحهٔ مرجع.
- سندِ فقط‑مرجوعیِ نیمستِ ۱۰٫۳۷ گرمی با اجرتِ ۱۱٪ → پیش از فیکس
- فیکسِ مالی سه خط است. در
docTaxBreakdownعلامتِ هر ردیف از خودِ ردیف میآید:var s = isRetRow(r) ? (r.retNoProfit ? 0 : -1) : 1; if (!s) return;و شرطِ خروج از
goldVal <= 0 && wageTot <= 0به!goldVal && !wageTotتغییر کرد، وگرنه سندِ فقط‑مرجوعی (که پایهاش منفی است)nullمیداد و همان باگ از درِ دیگر برمیگشت.r.retNoProfit === trueعمداًs = 0است: «سودش را برنگردان». rnd(v)— گِردکردنِ متقارن نسبت به صفر.Math.roundنصفهها را همیشه به سمتِ+∞میبرد، پسMath.round(-20546599.5) = -20546599ولی مثبتش20546600. با پایهٔ منفیِ مرجوعی، آینهٔ یک فروش ۲ ریال با خودش فرق میکرد و ادعای «جمعِ فروش و مرجوعی صفر است» میشکست.profitوtaxهر دو ازrndمیگذرند. این تنها جایی است کهrndلازم شد؛ بقیهٔMath.roundهای موتور روی قدرِ مطلق کار میکنند و علامت بعد از گِردکردن اعمال میشود.- مدلِ خالص (کنارِ
rowSign، پیش ازcomputeRowMag):rowDate(d, r)→ تاریخِ ردیف اگر باشد، وگرنه تاریخِ سند. هیچجاd.dateمستقیم برای یک ردیف خوانده نمیشود.docHasRowDates(d)→ آیا ردیفی با تاریخِ متفاوت از سربرگ هست. تنها منبعِ نمایشِ ستونِ «تاریخ».isRetRow(r)·retTypeOk(type)— دومی از خودِ کاتالوگِTASHKHISمیخواند (o.ret)، بدونِ فهرستِ موازیِ نوعِ سند؛ یک تست نگهبانِ همین است.retCanRow(d, r)— مرجوعِ مرجوعی، تخفیف، ردیفِ بیمقدار و سندِ «سایر» را رد میکند. مقدارداشتن باcomputeRowMagسنجیده میشود، نه با نگاه بهvazn، تا ردیفِ ارزی و سکه هم پوشش پیدا کند.retCloneRow(d, r, ri)— کلونِ عمیق (JSON.parse(JSON.stringify)) تاwageبین دو ردیف مشترک نماند.note/chk/retOf/retNoProfitحذف میشوند؛chkعمداً، چون چکِ برگشتی همان برگهٔ چک نیست و در دفترِ چک دوقلو میساخت.retOf = {docId, code, ri, date}.docPctPair(d)— درصدهای مؤثرِ سند (با پرکردن از تنظیمات) برای بردن به سندِ مرجوعیِ جدید. بدونِ این، عوضشدنِsettings.profitPctمبلغِ مرجوعیِ یک فاکتورِ پارسال را جابهجا میکرد.
retDo(i, where, noProfit)دو مسیر دارد. مسیرِ'same'باsplice(i + 1, 0, nr)ردیف را بیفاصله زیرِ فروش میگذارد. مسیرِ'new'سندِ تازه میسازد وpersonId/priceUnit/rate/taxOnو درصدهایdocPctPairرا کپی میکند، وnr.dateرا پاک میکند — سربرگِ سندِ جدید خودش امروز است، پس تاریخِ ردیفی معنا ندارد و ستونِ تاریخ بیدلیل ظاهر نمیشود. هیچکدامpersist()نمیکنند؛ بازبینی و ذخیره دستِ کاربر است.docAddRow(d)جایd.rows.push(blankRow())نشسته: اگر سربرگِ سند تاریخی جز امروز داشته باشد، ردیفِ تازهdate = todayJalali()میگیرد. کاربری که در سندِ ۲۸ ردیفِ امروز اضافه میکند، در ۹۹٪ موارد همین را میخواهد.retPeerGoods(d)فهرستِdatalist#dlRetGoodsرا از اقلامی میسازد که قبلاً با همین نوعِ سند به همین شخص رفتهاند. ردیفِ مرجوعی این فهرست را میگیرد و ردیفِ عادی همانdlDocGoodsقبلی را — چون نامِ ناهمخوان، درstkKeyدو قلمِ جدا میسازد و کاردکس را میشکند.- میانبرِ Ctrl+R روی
documentاست ولی سه شرطِ نگهبان دارد:docViewActive()، وجودِcurDoc، وretCanRow.retTargetRow()اول انتخابِ تکردیفیِ نوارِ v9 را میخواند و بعدdocument.activeElement.closest('tr[data-row]')را.e.preventDefault()فقط پس از عبور از هر سه شرط صدا میشود، پس reloadِ مرورگر بیرون از صفحهٔ سند دستنخورده میمانَد. - رندر. ستونِ تاریخ یک
<th>ِ شرطی است و همینcolspanِ ردیفِ تخفیف را جابهجا میکند:chkRowHtml(d, r, i, cols)پارامتری شد و باshowDt ? 13 : 12صدا زده میشود. ستونِ عملیات از48pxبه78pxرفت تا دکمهٔ ↩ کنارِ حذف جا شود.data-delحالاRENDER.doc()میزند نهrenderDocRows()— با رفتنِ ردیفِ دارای تاریخِ مستقل، سربرگِ جدول هم باید عوض شود. همین ادعا درtest-doc-flow.jsبهروز شد. - کاردکس.
stkLedgerتنها جایی بود که تاریخِ ردیف اهمیتِ محاسباتی دارد:var dt = rowDate(d, r)جایd.date. مرجوعیِ ۳۰ در بازهٔ «از ۲۹ به بعد» یک حرکت است و فروشِ ۲۸ درopenمینشیند؛ اتحادِclose = open + in − outبرقرار میمانَد. retOfChip(r)در همان سند یک<span>است و در سندِ دیگر یک<button data-retof>کهstkOpenDocرا صدا میزند.factorRowDescدو خطِc-retofوc-rdateرا روی فاکتورِ چاپی اضافه میکند.- CSS:
tr.ret-rowزمینهٔ--blue-softبا نوارِinset 3px 0 0 var(--blue)و واریانتِ تیره؛.row-acts،.icon-btn.ret،.row-date،.retof-chip، بلوکِ.ret-ask(ra-lead/ra-badge/ra-grid/ra-cell/ra-hint/ra-chk/ra-q) و دو کلاسِ چاپ.--blue/--blue-softاز پیش در هر دو تم بودند؛ مقدارِ پشتیبانِ داخلِvar()فقط احتیاط است. idها لفظی نوشته شدهاند (retNoProf) — همان درسِ v19: ساختِidبا الحاقِ رشته،lint-refs.jsرا کور میکند.- تست:
node scripts/test-return.js— ۱۱۴ بررسی در ۱۴ بخش، بدون مرورگر؛ شاملِ بازسازیِ عددیِ کاملِ سندِ ویدئو، اندازهگیریِ خودِ باگ (۲۵٬۰۱۳٬۷۰۰ و ۲۵٬۰۱۳٬۷۰۱)، تقارنِ دقیقِ فروش و مرجوعی، ناوردایی نسبت به نرخِ بازار و تنظیماتِ درصد، مرجوعیِ جزئی،retNoProfit، چهار حالتِretCanRow، جهتِ مرجوع در هر چهار نوعِ سند، سه بازهٔ کاردکس، بقای سودِ عیار، و سیمکشیِ رابط.
#سکهٔ پارسیان: اجرت عددی و معافیت ارزش افزوده (v21)
- دو قاعدهٔ مستقل که یک ویدئو با هم میآورد و عمداً جدا پیاده شدهاند: «اجرت به دانه بسته است» یک موضوعِ
wageRialاست و «ارزش افزوده ندارد» یک موضوعِdocTaxBreakdown. جنسی میتواند عددی و مشمول باشد، یا وزنی و معاف. wageRialحالتِ چهارم گرفت. پیش از این سه حالت بود (none/percent/فیِ گرمی). حالتِpiece:if (wg.mode === 'piece') return Math.round(num(r.tedad) * fi);متغیرِ
perGramبهfiتغییرِ نام داد چون دیگر همیشه «هر گرم» نیست. پشتیبانیِcur === 'dollar'بالای شاخه ماند تا هر دو حالتِ فی از آن بگذرند.docTaxBreakdown— معافیتِ ردیفی، با صفرِ regression. فرمول عمداً بهصورتِ «فرمولِ قبلی، منهای سهمِ ردیفهای معاف» نوشته شد، نه بهصورتِ جمعِ سطربهسطر:var profit = rnd((goldVal + wageTot) * pPct / 100); var exProfit = exGold || exWage ? rnd((exGold + exWage) * pPct / 100) : 0; var tax = rnd((wageTot - exWage + profit - exProfit) * vPct / 100);وقتی هیچ ردیفِ معافی نیست،
exWageوexProfitصفرند و عبارت کاراکتربهکاراکتر همان فرمولِ v20 میشود. جمعِ سطربهسطر (که کیمیا میکند) روی همین فاکتور ۱ ریال اختلاف میداد و ۱۷ سوئیتِ موجود را در معرضِ جابهجاییِ ±۱ میگذاشت — بهایی که برای هیچ نفعی پرداخت نمیشود.- معافیت پایهٔ سود را دست نمیزند، فقط پایهٔ مالیات را. پنجرهٔ فرمولِ خودِ نرمافزارِ مرجع سطرِ «سود تکفروشی ۲٬۲۸۰٬۴۶۰» را دارد و هیچ سطرِ مالیاتی ندارد. اگر سود هم معاف میشد، مبلغِ ردیف روی ۳۲٬۵۷۸٬۰۰۰ میماند نه ۳۴٬۸۵۸٬۴۶۰.
exGold/exWage/exProfitدر خروجی برمیگردند تا کارتِ مالیات بتواند «کسرِ معافیت» را نشان دهد. - اعدادِ فاکتورِ مرجع، بازتولیدشدهٔ دقیق (قیمتِ طلا ۱۵٬۰۸۹٬۰۰۰، سود ۷٪، مالیات ۹٪):
ردیف ورودی مبلغ دستبند رولکس ۲۳٫۹۲ گ · اجرت ۲۴٪ ۴۸۹٬۴۹۶٬۰۷۸ دستبند ظریف گوی ۹٫۰۴ گ · اجرت ۱۸٪ ۱۷۵٬۴۴۸٬۱۸۳ پارسیان (مشمول) و۷۵۰ ۲٫۰۰ · ۲ دانه × ۱٬۲۰۰٬۰۰۰ ۳۵٬۲۷۹٬۷۰۱ پارسیان (معاف) همان ۳۴٬۸۵۸٬۴۶۰ ماندهٔ سند ۳ ردیف / ۴ ردیف ۷۰۰٬۲۲۳٬۹۶۲ / ۷۳۵٬۰۸۲٬۴۲۲ اختلافِ دو ردیفِ پارسیان دقیقاً
rnd((2400000 + 2280460) * 9 / 100) = ۴۲۱٬۲۴۱است. r.noVatروی ردیف مینشیند، نه خواندهشده از کاتالوگ.applyGoodsTypeآن را کپی میکند (r.noVat = !!g.noVat). اگرrowNoVatکاتالوگ را میخواند، برداشتنِ تیکِ ارزش افزودهٔ پارسیان امروز، مالیاتِ فاکتورهای پارسال را هم پاک میکرد. یک تست همین ناوردایی را قفل میکند و ویدئوی مرجع هم بههمیندلیل میگوید ردیفِ قبلی را پاک کن.- تلهٔ
cashFi. برای جنسِ وزنی، «پیشنهاد فی نقدی» درr.fi(قیمتِ هر گرمِ طلا) مینشست. برای جنسِ عددی این کار فاجعه است: ۱٬۲۰۰٬۰۰۰ بهجای ۱۵٬۰۸۹٬۰۰۰ مینشیند و ردیف یکبیستمِ ارزشِ واقعیاش را نشان میدهد. پس شاخهٔg.perPieceFiپیش از آن خطreturnمیکند وcashFiرا درr.wage.fiمیریزد. یک تست مستقیماًr.fi === FIرا میسنجد. goldSyncUnitWeight(r)فقط وقتی کار میکند که همunitWو همtedadمقدار داشته باشند، و تا سه رقمِ اعشار گِرد میکند. پارسیانِ گلهایunitWeight = 0دارد، پس وزنِ دستیِ کاربر بازنویسی نمیشود — این باfalseبرگرداندن اعلام میشود، نه با استثنا.- تعداد اجباری، فقط همانجا که لازم است.
docQtyIssues(d)شمارهٔ ردیفهایwageIsPerPiece && !num(tedad)را برمیگرداند وsaveDocبلافاصله پس از بررسیِ «سند خالی» جلوی ثبت را میگیرد. جای دیگری تعداد اجباری نشد؛ فقط اینجاست که خالیبودنش مبلغ را بیصدا صفر میکند.wageFormهم در حالتِpieceبدونِ تعداد ثبت نمیشود. - ستونِ تعداد برای ردیفِ طلا باز شد (
r.kind === 'coin' || r.kind === 'goods' || r.kind === 'gold'). بدونِ این، اجرتِ عددی جایی برای گرفتنِ عدد نداشت. سلولِ خالیِ اجباری کلاسِcell-reqمیگیرد تا پیش از رسیدن به دکمهٔ ثبت دیده شود. - رندر و CSS:
novatFlag(d, r)فقط وقتی برچسب میزند که سند اصلاًtype === 'فروش' && taxOnباشد، وگرنه در فاکتورِ بیمالیات هر ردیف یک برچسبِ بیمعنی میگرفت..novat-flagعمداً سبز است نه قرمز — معافیت خطا نیست..pp-tagکنارِ خودِ عددِ اجرت مینشیند، همانجا که سؤال پیش میآید..tax-line.exemptبرای سطرِ «کسرِ معافیت». - هفت سوئیتِ موجود
rowNoVatرا به فهرستِFNSاضافه کردند — هارنسِ تستها تابعها را با برشِ متنی ازadmin.jsمیگیرد، پس هر وابستگیِ تازهٔdocTaxBreakdownباید صریحاً اعلام شود، وگرنهReferenceErrorمیدهد نه شکستِ منطقی. - تست:
node scripts/test-vat-exempt.js— ۱۲۲ بررسی در ۱۳ بخش؛ شاملِ هر چهار ردیفِ فاکتورِ مرجع لایهبهلایه، هر دو ماندهٔ سند، اختلافِ ۴۲۱٬۲۴۱، تفکیکِ ردیفِ معاف (سود هست، مالیات نیست)، معافیت در کنارِ مرجوعی، وزنِ یکعدد، مسیرِ کاتالوگ→ردیف، شمارشِ دانه در کاردکس، و یک بخشِ کاملِ عدمِ پسرفت که فاکتورِ v20 را دوباره میسنجد.
#فروش قسطی (v22)
- مدلِ داده: یک
r.inst.roleروی ردیف، یک عکسِd.instروی سربرگ. ردیفهای نقشه ردیفهای کاملاً عادیاند (blankRow()+ چند فیلد) که فقط یک نشانگر گرفتهاند. چهار نقش:due(تعهدِ آینده)،profit(سود قسط)،convRialوconvGold(جفتِ تبدیل). هیچ نوعِ ردیفِ تازهای بهROW_KINDSاضافه نشد، پس موتورِ مالی، مرجوعی، کاردکس و گزارشها همانطور که بودند کار میکنند. - ★ چرا تبدیلِ ریال به طلا دو ردیف است، نه یکی. نرمافزارِ مرجع یک ردیفِ «خرید پولی» دارد که همزمان ۳٫۹۱ گرم بدهکار و ۸۲٬۱۵۹٬۳۸۸ ریال بستانکار است. در این کدبیس چنین ردیفی ساختنی نیست، چون
docDeltaیک علامت را به هر دو دفتر میدهد:var mm = rowMult(d, r); g += mm * c.w750; ri += mm * c.rial;یعنی یک ردیف نمیتواند در طلا مثبت و در ریال منفی باشد. سه راهِ وسوسهانگیز بررسی و رد شد:
tashkhis: 'مرجوع'(هر دو را با هم برمیگرداند و ردیف را دروغین «مرجوعی» میکند،retOfChipو.ret-rowو معناشناسیِ مرجوع را روشن میکند)،kind: 'discount'(گزارشِ تخفیف را آلوده میکند)، و دستبردن درrowMult(تکْمنبعِ حقیقتِ جهت است و ۱۹ سوئیت رویش نشسته). راهِ انتخابی: دو ردیفِ همجهت که یکیfiمنفی دارد. نتیجهٔ خالص عیناً همان است — ماندهٔ ریالی صفر، ماندهٔ طلایی ۳٫۹۱ — بدونِ یک خط تغییر در موتورِ جهت. - ردیفِ قسط مبلغِ صفر دارد و این ستونِ فقراتِ درستیِ مانده است.
fi: ''و مبلغ/وزن فقط درr.inst.amt/r.inst.wtبرای نمایش نگه داشته میشوند. اگر ردیفِ قسط مبلغ میداشت، بدهی دوبار شمرده میشد. تنها ردیفی که بدهیِ تازه میسازدprofitاست، که در سندِ فروش باDIR['فروش'] = -1طبیعتاً بدهکار میشود. instApplyهمیشه اولinstClearرا صدا میزند. ویدئوی مرجع سه بار هشدار میدهد که برای تعویضِ ریالی↔طلایی باید ردیفها را دستی پاک کنی و در حالتِ طلایی ردیفِ «خرید پولی» را هم جدا برداری، وگرنه سود روی سود مینشیند. این یک تلهٔ رابطِ کاربری است، نه یک قاعدهٔ مالی — پس بسته شد. ثبتِ دوباره idempotent است و یک تست همین را قفل میکند.- گِردکردنِ دوباره در حالتِ طلایی، عمدی و آزمایششده:
var weight = r2(total / price); // ۷۶٬۰۶۰٬۴۲۹ ÷ ۲۲٬۰۰۰٬۰۰۰ → ۳٫۴۶ var monthlyWt = r2(weight / count); // ۳٫۴۶ ÷ ۴ = ۰٫۸۶۵ → ۰٫۸۷یکمرحلهای
r2(total / price / count)جوابِ ۰٫۸۶ میدهد که با هر چهار سندِ طلاییِ ویدئو میجنگد.r2رویrndسوار است (نهMath.round) تا نیمگِردِ منفی هم دور از صفر باشد. - درصد ⟷ سود دوطرفه، با
profitLocked. هر کدام که آخر تایپ شده باشد «قفل» است و دیگری از رویش برگردانده میشود (pct = profit * 100 / (debt * count)).draw()عمداً فیلدی را کهdocument.activeElementاست بازنویسی نمیکند، وگرنه مکاننما وسطِ تایپ میپرد. - تقویمِ جلالی بدونِ تقویمِ دوم. این فایل معکوسِ جلالی→میلادی ندارد. بهجای افزودنِ یکی،
jMonthLen(jy, jm)از اختلافِ اولِ دو ماهِ پیاپیِ خودِjDayساخته شد، پس دو تقویم هرگز واگرا نمیشوند و اسفندِ کبیسه خودبهخود درست درمیآید.jAddMonthsروزِ مقصد را به آخرِ ماه مهار میکند (۳۱ شهریور + ۱ ماه = ۳۰ مهر) وjAddDaysبا همانjMonthLenقدم میزند. - ★
jDowازtodayJalali()استفاده نمیکند — و دلیلش یک ناسازگاریِ واقعی است. دو تقویمِ داخلِ همین فایل یکی نیستند:toJalali(چرخهٔ ۳۳ساله) سالِ ۱۴۰۳ را کبیسه میگیرد،jDay(چرخهٔ ۲۸۲۰سالهٔ بیرشک) نمیگیرد. تقویمِ رسمیِ ایران هم نمیگیرد — نوروزِ ۱۴۰۴ روزِ ۲۰ مارس ۲۰۲۵ بود، یعنی ۱۴۰۳ فقط ۳۶۵ روز داشت وjDayدرست است. این دو در بازهٔ ۲۰۲۵/۰۳/۲۱ تا ۲۰۲۶/۰۳/۲۰ دقیقاً یک روز از هم فاصله میگرفتند. نسخهٔ اولِjDowروزِ هفته را از اختلافِ «امروز»ِ یک تقویم با سررسیدِ تقویمِ دیگر میساخت و در آن بازه تمامِ سالْ یک روز جابهجا میشد. حالا فقط ازjDayو یک لنگرِ ثابت میآید:var J_DOW_ANCHOR = '1403/01/01'; // = ۲۰ مارس ۲۰۲۴ = چهارشنبه return J_DOW[(((jDay(jNorm(s)) - jDay(J_DOW_ANCHOR)) % 7) + 7) % 7];هر شش تاریخی که روی سربرگِ نرمافزارِ مرجع در ویدئو دیده میشود، با همین فرمول تأیید شد. (خودِ باگِ
toJalaliعمداً دستنخورده ماند: خارج از دامنهٔ این تغییر است و بازهٔ واگرایی گذشته.) instDebtBase(d)ماندهٔ سند را بدونِ ردیفهای نقشهٔ فعلی حساب میکند (روی یک کپیِ فیلترشده). وگرنه هر بار که فرم را باز میکردی سودِ دورِ قبل پایهٔ سودِ تازه میشد و عدد بیسروصدا بزرگ میشد.- ردیفهای نقشه از پنلِ «ریز ورود ـ خروج» کنار میروند (
if (instIsRow(r)) return;درdocFlow). آن پنل برای تطبیق با ترازو و شمارشِ فیزیکی است؛ نشاندادنِ ۱۵٫۹۸ گرمِ «تبدیل بدهی» بهعنوانِ خروجِ طلا، کاربر را دنبالِ جنسی میفرستد که هیچوقت از مغازه بیرون نرفته. - ردیفِ
convGoldعمداًfi: 0دارد. بهاینترتیبrowProfit(که باif (!market || !fi) return nullشروع میشود) آن را نمیسنجد و سندِ قسطی هشدارِ دروغینِ «زیانِ فاحش» نمیگیرد.docTaxBreakdownهم سهمِ صفر از آن میگیرد، پس مالیاتِ سند تکان نمیخورد. - رندر و CSS:
instRowHtmlهمان ریاضیِ ستونیِdisc-rowرا دارد (dtCell+colspan=9+ سهtd)، پس با ستونِ اختیاریِ «تاریخِ ردیف» هم نمیشکند..inst-rowآبیِ ملایم است (همان قراردادِ ردیفِ فرعیِ چک: «این سطر مبلغِ سند را جابهجا نمیکند»)،.is-overقرمز، و ردیفهای مبلغدارِ نقشه فقط یک نوارِ کناری میگیرند (.inst-linked) تا محتوایشان خوانا و قابلِ ویرایش بماند. همهٔ رنگها از متغیرها میآیند، پس تمِ تیره بدونِ یک خطِ اضافه درست است. - اعدادِ بازتولیدشدهٔ ویدئو (هر شش سند، بدونِ اختلاف):
سند حالت ورودی خروجی ۱۱۴ ریالی ۷۳٬۱۵۹٬۳۸۸ · ۳٪ · ۴ سود ۸٬۷۷۹٬۱۲۷ · ماهیانه ۲۰٬۴۸۴٬۶۲۹ ۱۱۴ طلایی سودِ دستی ۹٬۰۰۰٬۰۰۰ · مظنه ۲۱٬۰۰۰٬۰۰۰ کل ۸۲٬۱۵۹٬۳۸۸ · ۳٫۹۱ گ · هر قسط ۰٫۹۸ گ ۱۱۵ طلایی ۶۷٬۹۱۱٬۰۹۷ · ۳٪ · ۴ · مظنه ۲۲٬۰۰۰٬۰۰۰ سود ۸٬۱۴۹٬۳۳۲ · ۳٫۴۶ گ · هر قسط ۰٫۸۷ گ ۱۱۵ ریالی همان بدهی · ۳٫۵٪ · ۴ سود ۹٬۵۰۷٬۵۵۴ · ماهیانه ۱۹٬۳۵۴٬۶۶۳ ۱۴۵ طلایی (بخشی) ۴۲۸٬۶۵۰٬۰۰۰ از ۵۱۱٬۳۴۰٬۲۱۱ · ۳٪ · ۴ سود ۵۱٬۴۳۸٬۰۰۰ · ۱۵٫۹۸ گ · هر قسط ۴٫۰۰ گ ۱۴۷ ریالی باقیماندهٔ ۸۲٬۶۹۰٬۲۱۱ · ۳٪ · ۴ سود ۹٬۹۲۲٬۸۲۵ · ماهیانه ۲۳٬۱۵۳٬۲۵۹
- تست:
node scripts/test-installment.js— ۱۳۵ بررسی در ۱۴ بخش؛ شاملِ هر شش سندِ بالا، صفرشدنِ ماندهٔ ریالی پس از تبدیل به طلا، تلهٔ گِردکردنِ ۰٫۸۶/۰٫۸۷، idempotent بودنِ ثبتِ دوباره، تعویضِ طلایی→ریالی، مهارِ روزِ آخرِ ماه، سالِ کبیسه (۱۴۰۳ کبیسه نیست، ۱۴۰۴ هست)، هر شش روزِ هفتهٔ خواندهشده از قابِ ویدئو، دورهٔ هفتگی، و یک بخشِ کاملِ عدمِ پسرفت.
#انتقال سند — ابزار قیچی (v23)
- بدونِ فیلدِ تازه و بدونِ migration: انتقال فقط
personId/personNameسندِ داخلِstate.docsرا عوض میکند وnetGold/netRialرا از نو میگیرد. سندِ تازه ساخته نمیشود، پسcodeوidوattachmentsو نقشهٔ قسط دستنخورده میمانند. - دفترِ فی داده نیست، مشتق است. جدولِ جداگانهای برای «آخرین فیِ هر قلم نزدِ هر شخص» نگه نمیداریم؛
lastFeeFor(personId, type, name, skipId)همان لحظه رویstate.docsمیگردد و تازهترینtsرا برمیدارد. کلیدِ تطبیقfeeKeyOf(r)=desc || sharhاست و نوعِ سند هم بخشی از کلید است — فیِ «دریافت» با فیِ «فروش» یکی نیست. skipIdلازم است، نه محضِ احتیاط: بدونش سندِ در حالِ انتقال مرجعِ خودش میشد و فی هرگز عوض نمیشد.feeRowish(r)فقطkindطلا/جنس و غیرِ مرجوعی را قبول میکند؛ ردیفِ تخفیف و مرجوع از انتقال بیاثر بیرون میمانند.docMovePlan(d, toId)هیچ چیزی را تغییر نمیدهد — همان نقشه هم به پیشنمایشِ پنجره میرود و هم بهdocMove، پس آنچه کاربر میبیند دقیقاً همان چیزی است که اجرا میشود.- قلمی که نزدِ شخصِ مقصد سابقه ندارد فیاش خالی میشود، نه اینکه فیِ شخصِ قبلی را نگه دارد. خالیِ آشکار از حدسِ خاموش بهتر است؛ toast هم تعدادِ ردیفهای بیفی را با لحنِ خطا اعلام میکند.
docIsSaved(d)نگهبانِ دکمه است: سندِ ذخیرهنشده اصلاً دکمهٔ انتقال نمیگیرد (طرفِ حسابش را مستقیم عوض کن).docMoveهم مستقل از UI همین را دوباره چک میکند، بهعلاوهٔ مقصدِ ناموجود و مقصدِ برابر با مبدأ.- تست:
node scripts/test-doc-move.js— ۳۵ بررسی؛ شاملِ تفکیکِ دفترِ فی بر اساس شخص و نوعِ سند، تازهترینبودنِ فی،skipId، بیاثری روی ردیفِ مرجوع/تخفیف، دستنخوردگیِ نقشه پیش از اجرا، ثبت در دفترِ کارها، هر سه ردِ منطقی، و رفتوبرگشتِ سند بین دو شخص.
#دریافت قسط (v24)
- هیچ فیلدی به نقشهٔ v22 اضافه نشد. جدولِ سرشکن داده نیست، مشتق است:
instSchedule(sale)هر بار از روی ردیفهایrole:'due'و سندهای پرداختِ همان فروش ساخته میشود. پس ویرایشِ سررسید یا حذفِ یک پرداخت، همهچیز را خودکار درست میکند و هیچجا عددِ کهنه نمیماند. - فرمولِ تتمّه:
سهمِ خامِ n = cumShare(n) − cumShare(n−1) cumShare(n) = کل × n ÷ تعداد (آخری: دقیقاً کل) مقررِ n = سهمِ خام + تتمّهٔ n−۱ فقط اگر n−۱ پرداختی خورده باشد تتمّهٔ n = مقررِ n − Σ پرداختهای nقسطِ دستنخورده تتمّه پخش نمیکند (سرِ جای خودش باز میماند) و تتمّهٔ قسطِ آخر جایی برای رفتن ندارد، پس همانجا مانده میشود.
Σ paid + Σ rest == totalهمیشه برقرار است. - گِردکردن، جای درستش: سهمِ تجمعی خام میماند؛ فقط پرداختی که با مظنه تبدیل شده گِرد میشود (طلا به سوت، ریال به ریال). اگر پرداختِ دوم را گِرد نکنی، قسطِ سومِ مثالِ طلایی بهجای ۳٫۹۵ میشود ۳٫۹۴.
instUnitRoundعمداً ۱e−۶ ارفاق دارد چون تفریقِ دو سهمِ تجمعی ۳٫۹۴۵ را به3.9449999999999994تبدیل میکند و یک سوت گم میشد. d.instPay = {saleId, saleCode, n, of, unit, credit, rial, form, price, method}— هر پرداخت از همان اول به شمارهٔ قسط قفل است. تلهٔ ویدئو («اول روی ردیفِ قسط کلیک کن، بعد کارتخوان») اینجا اصلاً ممکن نیست.- ساختِ ردیفها: خالصِ سند باید فقط محورِ تعهد را بهاندازهٔ
creditتکان بدهد. جنسی که روی آن محور نیست (سکه همیشه، طلا در قسطِ ریالی) با ردیفِrole:'neutral'وfi:0خنثی میشود — همان ترفندِ دوردیفیِconvRial/convGoldدر v22، چون موتورِ جهت برای هر ردیف فقط یک علامت دارد. خودِ جنس باrole:'phys'میماند تا کاردکس صادق بماند. - سندِ سمتِ بانک: اثرِ یک سند روی حساب برابرِ
docTotals(doc).rialهمان سند است. اگر جمعِ ریالیِ سندِ شخص با پولِ دریافتی یکی بود، حساب به همان سند میچسبد؛ وگرنه سندِ «دریافت» جداگانه باpersonId:''وinstPayBankOf: <id سندِ شخص>ساخته میشود — همان الگویmkBankSideDoc/doLoanReceive/doPosSettle. instNotionalRow(r)(= ردیفِ قسط کهrole !== 'phys') جایگزینِinstIsRowدر دو صافی شد:docFlowوstkRowSubj. علاوه بر ردیفهای تازه، یک باگِ v22 را هم میبندد: ردیفِ «تبدیل بدهی به طلا» پیشتر بهعنوان قلمِ جعلی وارد کاردکس میشد.- توابع:
instCumShare·instSchedule·instPayPlan(فقط حساب میکند، چیزی نمینویسد — پیشنمایش و ثبت از یک منبع میآیند) ·instPayApply·instPayForm·instDueList/instDuePanelHtml(پنلِ داشبورد) ·INST_FORMS/INST_METHODS. - تست:
node scripts/test-instpay.js— ۱۳۹ بررسی در ۱۱ بخش؛ شاملِ هر دو سندِ مرجعِ ویدئو عدد به عدد، ماندهٔ واقعیِ حساب پس از هر پرداخت، خنثیشدنِ محورِ سکه و طلا، کمدادن و زیاددادن، اصلِ بقا، دو سندیشدنِ بانک، اعتبارسنجیِ فرم، فهرستِ سررسید، و یک بخشِ عدمِ پسرفت برای v22.
#ریشهٔ وب فقط پسوندِ شناختهشده را میدهد (v25)
- چرا: روی سرور ۱۳۵ نسخهٔ پشتیبانِ سورس جمع شده بود — ۱۱۳ فایل مثل
admin.js.bak-20260810-125847کنارِ فایلهای اصلی و ۲۲ فایل در پوشهٔ مخفیِpublic/.bak/. چونserveStaticهر چیزی را باapplication/octet-streamمیداد، همه بدون احراز هویت با ۲۰۰ دانلود میشدند؛ یعنی کلِ سورسِ پنل و تاریخچهاش در دسترس بود.lsساده هم پوشهٔ نقطهدار را نشان نمیداد، پس پاکسازیِ دستی مطمئن نیست. - قاعده:
SERVABLE_EXT = کلیدهای MIME ∪ مقادیر ATTACH_EXT— یعنی.html .css .js .json .png .svg .jpg .jpeg .webp .gifبهعلاوهٔ پیوستها.pdf .txt .doc .docx .xls .xlsx. هر پسوندِ دیگر ۴۰۴. علاوه بر آن، اگر هر بخشی از مسیر با نقطه شروع شود (/.bak/…) هم ۴۰۴ است. - فهرست از روی همان دو جدولِ موجود ساخته میشود، پس با افزودنِ نوعِ پیوستِ تازه خودبهخود هماهنگ میماند و جای دومی برای بهروزرسانی نیست.
- نکته هنگام افزودنِ نوعِ فایلِ تازه: اگر روزی مثلاً فونت
.woff2بهpublic/اضافه شد، باید بهMIMEافزوده شود وگرنه ۴۰۴ میگیرد. - تست: بخشِ ۵ در
node scripts/test-server-body.js— با سرورِ واقعی میآزماید که.bak-<تاریخ>،.bak2-…، پسوندِ عددی، فایلِ~دار و پوشهٔ مخفی ۴۰۴ بگیرند و در همان حال/،/adminوstyles.css۲۰۰ بمانند.
#صفحهٔ راهنما ساخته میشود، نوشته نمیشود (v26)
- چرا:
public/rahnama.htmlیک صفحهٔ دستسازِ ۱۶ کیلوبایتی با ۶ موضوعِ پایه بود، در حالی که همین سند ۴۵ بخش و ۲۲۶ زیربخش دارد. صفحهٔ دستساز از روزِ دوم عقب میافتد. حالا از روی همین فایل تولید میشود:node scripts/build-rahnama.js. - قاعدهٔ اسلاگ عیناً از
check-doc-links.jsکپی شده (\p{L}\p{N}\p{M}\u200cنگه داشته میشوند، بقیه حذف، فاصله→-). اگر این دو از هم جدا بیفتند، لینکهای داخلیِ سند در HTML میشکنند. سرتیترِ همنام (اشتباهِ رایجشش بار) با پسوندِ-2،-3… یکتا میشود و اولی اسلاگِ پایه را نگه میدارد تا لینکهای موجود نشکنند. - بلوکِ داخلِ آیتمِ لیست. سند ۹ کدفنس، ۳ جدول و ۶ نقلقول را تورفته زیرِ یک آیتمِ لیست دارد. مبدلِ سادهای که اینها را «متنِ ادامه» بگیرد، بکتیک و سطرِ
|را خام روی صفحه میریزد.renderListبرای هر آیتم یک لیستِ بلوک نگه میدارد (ul/code/table/quote/p) و حالتِ فنس را دنبال میکند. تورفتگیِ بدنه دو فاصله است، مگر نقلقولِ زیرِ لیستِ شمارهدار که سه فاصله است. - پررنگِ غیرحریص.
**الف *ب* ج**با الگوی\*\*([^*]+)\*\*رد میشد و**خام میماند. الگو به\*\*([\s\S]+?)\*\*تغییر کرد و پیش از پاسِ مورب اجرا میشود. - صحتسنجیِ خروجی (بدون مرورگر): صفر لینکِ داخلیِ شکسته از ۴۲۷ لینک، صفر
**/بکتیکِ خامِ بیرون از<code>، تگهای متوازن، و برابریِ شمارش با سند — ۴۵h2، ۲۲۶h3، ۴۳۹<tr>، ۲۱<pre>. - ورود از پنل: آخرین آیتمِ منو،
<a data-ext="1" href="rahnama.html" target="_blank">. عمداًdata-viewندارد؛ در عوض دو جایadmin.jsکه فرض میکردند هر.nav aسربرگ است باdata-extمحافظت شدند: هندلرِ کلیک (وگرنهgo(undefined)) وapplyAccess(وگرنهcanView(undefined)پنهانش میکرد).
#جستجوی چیدمانِ کیبورد و پیشنهادِ فازیِ کالا (v27)
- چرا: ویدئوی مرجع سه چیز نشان میداد که نداشتیم — تایپِ
ugو رسیدن به «علیرضا»، تایپِد بدر ستونِ شرح و رسیدن به «دستبند بچگانه»، و ذرهبینی که بهجای فهرست، خودِ فاکتور را باز میکند. KB_FAنگاشتِ چیدمانِ استانداردِ فارسی (ISIRI 9147) است: کلیدِ فیزیکی → حرفِ فارسی.kbFa(s)اگر هیچ حرفِ لاتینی نبود رشتهٔ خالی برمیگرداند تاfuzzyScoreبیجهت دو بار امتیاز نگیرد.- ترتیب مهم است. نگاشت پیش از
normSearchاعمال میشود، وگرنه کلیدهای علامتیشکل که حرفِ فارسی دارند ([= ج،;= ک،'= گ،,= و) در پاکسازی از بین میروند. به همین دلیلsearchPersonsعبارتِ خام را بهpersonMatchScoreمیدهد، نهqnرا. fuzzyScoreپوسته شد و هستهٔ امتیازدهیscoreOneنام گرفت. خوانشِ فارسی و خوانشِ «کیبورد انگلیسی مانده بود» هر دو سنجیده وMath.maxگرفته میشود — پس جستجوی واقعاً لاتین (بارکد، نامِ انگلیسی) از دست نمیرود.initialsScoreحروفِ اولِ واژههای پشتِسرِ هم را میسنجد (۰٫۸۸اگر از واژهٔ اول شروع شود، وگرنه۰٫۸۲) و روی عبارتِ تکحرفی کار نمیکند.- بیتفاوتی به فاصله (
دست بند=دستبند) بعد از حروفِ اول سنجیده میشود، نه قبلش — وگرنهد ببهجای «دستبند بچگانه» با امتیازِ پایینترِ زیررشتهای گیر میکرد. goodsSuggestجای<datalist>را گرفت در ستونِ شرح (data-gs="all|ret").dlRetGoodsحذف شد. یک جعبهٔ مشترکِposition:fixedرویbodyمیماند، نه یکی بهازای هر ردیف: جدولِ سند با هر تغییرinnerHTMLمیشود و جعبههای داخلی هر بار دور ریخته میشدند؛fixedهم لازم است تا ازoverflow:autoجدول بیرون بزند.namesOf()هر بار تازه خوانده میشود چون فهرستِ مرجوعی به طرفِ حسابِ سند وابسته است.docCodeBtn(ذرهبینِ نوارِ بالا) عمداً برابرِ دقیق تطبیق میدهد نه فازی: بازکردنِ سندِ اشتباه بدتر از پیدا نکردنِ آن است.spanقبلی بهbuttonتبدیل شد.- تست:
node scripts/test-search.js— ۶۴ بررسی؛ شاملِ کلِ نگاشتِ کیبورد، هر دو مثالِ ویدئو، حروفِ اول با و بدون فاصله، بیتفاوتی به فاصله، ترتیبِ امتیازها، و اینکه جستجوی لاتینِ واقعی نشکند.
#ترازِ ارز و سکه (v27)
- چرا جدولِ جدا و نه ستونِ تازه در دفترِ تراز: طلا یک واحد دارد (گ۷۵۰) پس یک ستون بس است، ولی سکه به تفکیکِ نوع و ارز به تفکیکِ واحد تراز میشود. یک ستونِ مشترک یا باید جمعِ بیمعنیِ «تمام + ربع» بدهد یا دلار و درهم را روی هم بریزد. پس هر قلم یک سطر است.
balFxLedger(range)روی همانbalDocs(range)وrowMult(d, r)ِ دفترِ تراز کار میکند تا جهتها هرگز از هم جدا نیفتند. ردیفِkind:'coin'تعدادش شمرده میشود؛ بقیه ازcomputeRowMag(r)فقط وقتی حساب میشوند کهc.curداشته باشند — یعنی همان منبعی کهdocDeltaمیخواند.balFxAmtسکه را عددی و ارز را با جداکنندهٔ هزارگان نشان میدهد؛ هیچکدام قالبِ ریالی نمیگیرند. آستانهٔ صفر هم فرق دارد:۰٫۰۰۵برای سکه در برابرِBAL_EPSبرای ارز.- تنظیمِ
balFx(پیشفرضoff) در هر دو فرم است — تبِ تنظیمات و پنجرهٔ راستکلیکِ نوار — و درbalBarOn()هم شرکت میکند، پس با خاموش بودنِ طلا و مبلغ هم میتواند نوار را زنده نگه دارد. روی نوار حداکثرBAL_FX_CHIPS = ۳قلمِ نامتراز مینشیند. - تست: بخشِ ۱۲ در
node scripts/test-bal.js(مجموع ۷۷ بررسی).
#سنگ و نگین روی ردیف سند (v28)
- چرا: پیش از این
stoneLeatherFormفقط در تبِ انبار بود، فقط گرم و ریال میفهمید، حلکننده نداشت و اصلاً روی ردیفِ سند دیده نمیشد.hasStoneهم روی نوعِ کالا ذخیره میشد ولی هیچجا خوانده نمیشد. ویدئوی مرجع سه چیزِ نداشته را نشان میداد: قیراط، دلار، و ماشینحسابِ خودتکمیل. - سنگ وزن نیست، مبلغ است.
computeRowMagفقط بهrialدست میزند وw750را نمیبیند. دلیلش قاعدهٔ واقعیِ بازار است: لیبلِ بنکدار وزنِ خالصِ طلا را دارد و وزن سنگ از قبل کسر شده. اگر سنگ به گرمِ ۷۵۰ اضافه میشد، ماندهٔ طلاییِ مشتری و کاردکسِ موجودی هر دو با سنگ باد میکردند.stoneGramفقط داخلِ حلکننده مصرف میشود، نه در حسابداری. stoneRialعمداً کپیِ ساختارِwageRialاست: سه حالت، وcur === 'dollar'که باLIVE.dollarریالی میشود. هرجا اجرتِ دلاری معنی میدهد، سنگِ دلاری هم همانجا و با همان قاعده معنی میدهد؛ دو موتورِ ارزیِ موازی نساختیم.- جای سنگ در فرمولِ مالیات کنارِ اجرت است، نه کنارِ طلای خام — از تصویرِ فرمولِ خودِ نرمافزار در ویدئو:
profit = (goldVal + wage + stone) × pPctوtax = (wage − exWage + stone − exStone + profit − exProfit) × vPct. طلای خام از ارزش افزوده معاف است و سنگ نیست؛ اگر سنگ هم معاف گرفته میشد مالیاتِ هر فاکتورِ نگیندار کمتر از واقعیت درمیآمد.exStoneدقیقاً موازیِexWageاضافه شد تا معافیتِ ردیفی (v21) نشکند. - شرطِ
if (!goldVal && !wageTot && !stoneTot) return null;— بدونِstoneTot، ردیفی که فقط سنگ دارد (طلای صفر) کلِ تفکیک را خالی برمیگرداند و مالیاتش بیصدا صفر میشد. stoneSolveهفت خانه را با سه رابطه و چهار پاس میبندد (وزن کل / وزن سنگ / قیمت). چهار پاس لازم است چون زنجیرهها به هم وابستهاند: از «تعداد × وزنِ یکدانه» وزنِ سنگ درمیآید و تازه بعدش فی از قیمتِ کل. تابع خالص است و فقط خانههایnullرا پر میکند — پس ورودیِ کاربر هرگز بازنویسی نمیشود و تست بدون DOM اجرا میشود.r.vaznاز خانهٔ «وزن طلا»ی فرم نوشته میشود، نه از «وزن کل». فرم میتواند وزنِ ناخالص بگیرد، ولی چیزی که به حسابداری میرسد همیشه وزنِ طلاست.- دو پنجرهٔ همنام نداریم:
stoneForm(rowIdx)رویcurDoc.rowsاست وstoneLeatherForm(rowIdx)سرِ جای خودش رویstate.inv.goodsمانده. تست شمارشِ هر دو را قفل کرده تا کسی یکی را جای دیگری صدا نزند. applyGoodsTypeفقط وقتیg.hasStoneباشد و ردیف سنگ نداشته باشد پیشفرض میریزد (g.stone= نام/واحد/روش/ارز)، و برای کالای غیرطلایی زودترreturnمیکند — سنگ فقط روی ردیفِ طلا معنی دارد.- تست:
node scripts/test-stone.js— ۱۱۹ بررسی در ۱۰ بخش؛ شاملِ هر دو مثالِ ویدئو (عقیق و فیروزهٔ مبلغی، یاقوتِ قیراطیِ دلاری)، همهٔ مسیرهای حلکننده در هر دو جهت، فرمولِ سود و مالیات با و بدون معافیت، و بیاثر بودنِ سنگ روی گرمِ ۷۵۰.
#دفتر روزانه (v29)
- چرا: پیش از این تنها چیزی که «دفتر روزانه» نام داشت یک پنلِ کوچک داخلِ صفحهٔ گزارشها بود که فقط حواله و کارتخوان را نشان میداد (و راهنما هم صادقانه نوشته بود «در حال توسعه»). گزارشِ واقعی یک برشِ زمانی از همهٔ ردیفهای همهٔ اسناد است، پس صفحهٔ مستقلِ خودش را گرفت:
daybookدرALL_VIEWS،TITLESو منوی کناری. پنلِ حواله/کارتخوان سرِ جایش ماند چون خلاصهٔ موضوعیِ همان دو مورد است، نه دفترِ روزانه. - واحدِ گزارش ردیف است نه سند.
dbLines()رویstate.docsمرتبشده بر (تاریخ، ts) میچرخد و برای هر ردیفِrowHasValueیک «خط» میسازد.DB.summaryهمین را بهdocDeltaهر سند فرو میکاهد — یک خط برای هر فاکتور. - جهت از
rowMultمیآید، نه از نوعِ سند.dbDirOfفقط علامت را بهin/out/noneترجمه میکند. نتیجه: «مرجوع» و تشخیصهای مطلقِ «ورود»/«خروج» بدون هیچ شرطِ اضافه در ستونِ درست مینشینند.mm === 0(سندِ «سایر» بدون تشخیص) عمداًnoneمیشود و در هیچ ستونی جمع نمیخورد — وگرنه جمعِ ستون دروغ میشد. - خطِ جداگانهٔ سود و مالیات، تصمیمِ اصلیِ این گزارش است.
docTaxBreakdown(d).extraدرdocDeltaبه ماندهٔ شخص میرود ولی به هیچ ردیفی تعلق ندارد. اگر نادیده گرفته میشد،Σ خطها ≠ Σ docDeltaبود. تست این تساوی را برای هر دو سمت (طلا و ریال) قفل کرده است. DB.splitPctجمع را عوض نمیکند، فقط تفکیک میکند: از خطِ اصلیmm × (wage + stone)کم و همان مقدار در خطِ «بابت درصد» اضافه میشود. تست، برابریِ جمعِ روشن و خاموش را میسنجد.- قرارداد فیلترها: آرایهٔ خالی یعنی «همه». پنج کارتِ
dbFilterHtmlروی همین قرارداد کار میکنند، پس فیلترها باANDروی هم جمع میشوند و انتخابهای داخلِ یک کارت باOR. در حالتِmode === 'all'هر دو تابعِdbDocPass/dbRowPassبیقیدtrueبرمیگردانند — یعنی «هر چی که هست» یک مسیرِ کد است، نه یک حالتِ فیلترِ خاص. dbDocNos()شمارهٔ سندِ هر طرف حساب را جدا از کد سراسری میسازد (شمارشِ ترتیبیِ اسنادِ همانpersonId). ستونِ «کد سند» و ستونِ «سند» عمداً دو چیزِ متفاوتاند، همانطور که در ویدئوی مرجع هستند.- جستوجو روی
dbLineText(l)و با همانfuzzyScoreبقیهٔ برنامه انجام میشود (آستانهٔ ۰٫۴۵) — یعنی غلط املایی، ی/ک عربی و چیدمانِ انگلیسیِ کیبورد همینجا هم کار میکند و موتورِ جستجوی دومی ساخته نشد. - نشانگذاری با Space در
localStorageمیماند، نه درstate. «تا کجا بررسی کردهام» یک یادداشتِ شخصیِ همان کاربر است؛ اگر روی سرور ذخیره میشد، نشانِ یک حسابدار روی صفحهٔ بقیه هم ظاهر میشد. کلید:goldapp_dbmarks. rowHasValue(r)بهعنوان تابعِ مشترک اضافه شد (همان شرطی که پیشتر داخلِretCanRowتکرار شده بود) تا ردیفِ نیمهکاره خطِ خالی نسازد.- تداخلِ نام: کلاسِ
.db-subقبلاً نوارِ زیرِ پنلِ حواله بود، پس شرحِ فرعیِ جدول.dbk-subنام گرفت. تست این را هم قفل کرده تا کسی دوباره یکیشان نکند. - تست:
node scripts/test-daybook.js— ۱۱۹ بررسی در ۱۲ بخش؛ شاملِ تساویِ جمعِ ستونها باdocDelta(با و بدون مالیات)، بیاثر بودنِ «چاپ درصدها» روی جمع، هر هشت بازهٔ زمانی، همهٔ کارتهای فیلتر، و مرجوعی و ورود/خروجِ مطلق.
#تاریخچه کارها (v30)
- چرا: کدبیس از قبل
logAction(act, detail)وstate.auditرا داشت — یک لاگِ تخت با چهار فیلد (ts,user,act,detail) که فقط در یک تبِ کوچکِ اتاق فرمان دیده میشد. برای پرسشی که این نسخه جواب میدهد («کدام عدد از چه به چه رفت») بیفایده بود: نه فیلدی داشت، نه مقدارِ قبلی، نه عکسِ حذفشده. logActionحذف نشد، به یک لایهٔ نازک تبدیل شد. امضایش دستنخورده ماند تا هر ۳۶ فراخوانیِ موجود بدون تغییر کار کنند؛ حالا بهlogEventمیرسد و رکوردِ ساختیافته میسازد. پارامترِ سومِ اختیاری همان جزئیاتِ ساختیافته است و هرجا داده نشود،histMeta(act)از روی متنِactحدس میزند (دو جدولِHIST_EV_RULESوHIST_ENT_RULES، اولین تطبیق برنده).histNorm(e)همین حدس را هنگام خواندن روی رکوردهای قدیمی هم میزند، پس لاگِ موجودِ سرور بدون migration در گزارشِ تازه ظاهر میشود.newکلمهٔ کلیدی است، پس فیلدِ مقدارِ جدید در کلِ ماژولnwنام دارد.- تنها نقطهٔ گرفتنِ تفاوت،
saveDoc()است. پنل هیچ قلابِ per-keystroke ندارد و نباید هم داشته باشد: ردیفی که کاربر در فرم پاک کرده ولی ذخیره نکرده، اصلاً حذف نشده.saveDocتنها گلوگاهی است که هم نسخهٔ ذخیرهشده و هم نسخهٔ کاری را با هم دارد.if (ex) { histLogDocEdit(ex, d); Object.assign(ex, d); } else { state.docs.push(...); histLogNewDoc(d); }ترتیب حیاتی است: تفاوت باید قبل از
Object.assignگرفته شود، وگرنه شیء با خودش مقایسه میشود. باgrepروی همهٔ انتسابهایcurDocبررسی شد که همیشهJSON.parse(JSON.stringify(...))است و هرگز به شیءِ داخلِstate.docsalias نمیشود؛ پس مقایسهٔ قبل/بعد معتبر است. - جفتکردنِ ردیفها با امضا، نه با اندیس — تصمیمِ اصلیِ این نسخه. مقایسهٔ
A[i]باB[i]روی حذفِ ردیفِ وسط، آبشاری از «ویرایش»های دروغین میسازد و خودِ حذف را گم میکند.histPairRows(A, B)سه پاس میزند با کلیدهایی که هر بار آسانگیرتر میشوند (histKey(r, lvl)):سطح کلید چه چیزی را میگیرد ۰ نوع + شرح + وزن + عیار + فی + تعداد ردیفِ دستنخورده ۱ نوع + شرح همان کالا، عددهایش عوض شده ۲ نوع + عددها شرح عوض شده، عددها ثابت باقیماندهٔ هر دو طرف بهترتیب جفت میشود و اضافهها
del/addمیشوند. کلیدِ خالی (شرحِ خالی در سطح ۱، همهٔ عددها صفر در سطح ۲) رد میشود تا جفتِ بیمعنی نسازد. سطحِ ۱ و ۲ در بازبینی اضافه شدند: تستِ «حذفِ یکی و ویرایشِ دیگری با هم» با تکپاسِ اولیه رد میشد، چون باقیماندهٔ ترتیبی، ردیفِ حذفشده را به ردیفِ ویرایششده میچسباند. - سه جدولِ فیلد، بهجای شرطِ پراکنده:
HIST_DOC_FIELDS(تاریخ، نوع سند، طرف حساب، واحد قیمت، مالیات سند…) ·HIST_ROW_FIELDS(خانههای خامِ ردیف) ·HIST_ROW_CALC(خانههای محاسباتی با تابعِ استخراج:درصد اجرت,اجرت عددی,سنگ,وزن ۷۵۰,مبلغ). خانهٔ محاسباتی عمداً هست: کاربر «مبلغ» را تایپ نمیکند ولی آن چیزی که در تراز جابهجا میشود همین است.histFmt(v, kind)هر مقدار را با همان قالبِ بقیهٔ برنامه (money,wt,faDate, …) به متن تبدیل میکند تا مقایسه و نمایش هر دو خوانا باشند. - عکسِ حذف (
snap) تنها نسخهٔ باقیماندهٔ یک ردیفِ پاکشده است، پس در همان لحظه ساخته و ذخیره میشود؛histRowSnapسرِ سند را هم داخلش میگذارد (کد، تاریخ، نوع، طرف حساب) چون بعد از حذف، ردیف دیگر هیچ زمینهای ندارد.histObjSnap(obj, fields)همین را برای شخص (HIST_PERSON_FIELDS)، قبضِ ذوب (HIST_MELT_FIELDS) و کاربر (HIST_STAFF_FIELDS) انجام میدهد و رویnullآرایهٔ خالی میدهد. HIST_MAX = 4000و برشِslice(-HIST_MAX)درlogEvent. کلِ دفتر در یک POST ذخیره میشود (§ باگیابیِ سرور، v15)، پس لاگِ بیمهار مستقیم به حجمِ هر ذخیره میرود.HSدقیقاً موازیِDBِ دفتر روزانه است و همانDB_PRESETSرا مصرف میکند، ولیhsRange()رویe.ts(زمانِ انجامِ کار) اعمال میشود نهd.date. همین یک تفاوت، کلِ تمایزِ دو گزارش است.dbCard/dbChkListهم دوباره استفاده شدند تا پنلِ فیلترِ دومی ساخته نشود.- جای ماژول در فایل: انتهای
admin.js، بعد از listenerِ کلیدِFِ دفتر روزانه. امن است چونlogEvent/histMeta/histObjSnapتابعِ اعلانیاند (hoist میشوند) و جدولهایHIST_*فقط داخلِ handlerهایی خوانده میشوند که خیلی بعد از اجرای بدنهٔ IIFE اجرا میشوند. - ثبتهای جانبی:
historyدرALL_VIEWSوTITLES؛#view-historyو آیتمِ منو درadmin.html؛ بلوکِ.hs-*درadmin.css(ستونِ قرمزِhs-old، آبیِhs-new، نشانِhs-evدر پنج حالت، جداکنندهٔ چسبانِhs-daysep). در تبِ لاگِ اتاق فرمان دکمهٔ رفتن به صفحهٔ تازه اضافه شد و متنِ تأییدِ «پاک کردن لاگ» هشدار میدهد که تاریخچه هم پاک میشود. - CSV با
\ufeffشروع میشود وگرنه اکسلِ فارسی فایل را با انکودینگِ محلی باز میکند و کلِ ستونها را بههم میریزد. - تست:
node scripts/test-history.js— ۱۰۵ بررسی در ۷ بخش؛ شاملِ حدسِ رویداد/تراکنش و ارتقای رکوردِ قدیمی، تفاوتِ فیلدبهفیلد با مقدارِ قبلی/جدید (از جمله خانههای محاسباتی)، هر چهار حالتِ جفتکردنِ ردیف (حذفِ وسط، افزودن، جابهجایی، حذف+ویرایشِ همزمان)، اعمالِ بازه روی زمانِ کار بهجای تاریخِ سند، و اتصالِ صفحه به HTML/CSS/راهنما.
#اجاره طلا (v31)
- مسئلهٔ اصلی حسابداری بود، نه رابط کاربری. موتورِ ما به هر ردیف یک
rowMultمیدهد که هم روی وزن و هم روی مبلغ اعمال میشود؛ نرمافزارِ مرجع میتواند در یک ردیف وزن و پول را در دو جهتِ مخالف ببرد. پیش از نوشتن یک خط از ماژول، شکلِ سند با یک هارنسِ آزمایشی (docDeltaروی ترکیبهای مختلف) تجربی درآمد. نتیجه: سندِ «سایر» با تشخیصِ مطلقِورود/خروجروی هر ردیف — چونTASHKHIS['سایر']جهت را از سربرگ نمیگیرد و همین اجازه میدهد یک سند همزمان بستانکار کند و بپردازد. SHARH_CODESکد ۹ «اضافه» گرفت، و این تنها کدِ شرحی است که واقعاً کار میکند. کد ۸ «کسر» از قبل وجود داشت ولیkind: 'discount'و ریالی است — مفهومِ قرینه، نه همان. برای همین کد تازه گرفت و کد ۸ دست نخورد.isAddRow(r)تکْمنبعِ تشخیص است:r.kind === 'gold' && r.sharh === '9'.- سه استثنا و یک الزام — همان چیزی که «اضافه» را از یک برچسبِ ساده جدا میکند:
stkRowSubj→null(کاردکس): جنسی از در تو نیامده که ردیابی شود.docFlow→return(پنلِ ورود ـ خروج): همان دلیل.perfBucketOf→null(کارکردِ معاملات): ردیف فی ندارد؛ اگر میماند،rowDayProfitآن را جنسِ مجانی میدید و یک سودِ ساختگیِ هماندازهٔ نرخِ روز میساخت.perfReport→ باید بیاید: انباشتِaddGoldبا علامتِ-rowMult(d, r) * rowW750(r)و سطرِ «اضافه و اجارهٔ طلا» درothers. علامت عمداً عکسِ جهتِ ردیف است — بستانکار کردنِ طرف یعنی زیانِ ما.
- پرداختِ پولی دو سند است، نه یکی.
cashBalances()وacctDocDelta()فقط سندهایدریافت/پرداخترا میشمارند. اگر لِنگِ پرداخت داخلِ همان سندِ «سایر» میماند، ماندهٔ شخص درست میشد ولی پول از هیچ صندوقی خارج نمیشد. پسleasePostRentدر حالتِcashیک سندِ «سایر» (اضافه + پولی کردن + معادلِ ریالی) و یک سندِ پرداخت باcashIdیاbankKind/bankIdمیسازد.mkLeaseDoc(..., opt)برای همین پارامترِ پنجم را گرفت. leaseStats(l)منبعِ همهٔ عددهای صفحه است وexpected = principal + (accrued − settled)را باactual = balances()[personId].goldمیسنجد. تفاوتشانdriftاست — همان چیزی که کارتِ قرمز را روشن میکند.leaseDriftEps(periods) = 0.005 + 0.001 × periods. آستانهٔ ثابتِ نیمسوت جواب نمیداد: ۹٫۹۵۰ گرمِ ۷۵۰ که به ۱۰٫۰۸۴ گرمِ ۷۴۰ تبدیل و گِرد میشود، در برگشت ۹٫۹۴۹ است. این ریزه هر دوره تکرار میشود و بعد از یک سال ۵ سوت میشود — با آستانهٔ ثابت، هر قراردادِ سالمِ یکساله کارتِ قرمز میگرفت.owingهم زیرِ همین آستانه صفر گزارش میشود.- زیرحسابِ جدا (
leaseAccount) با پسوندِLEASE_SUFFIXو نوعِ «سرمایهگذار» ساخته میشود؛ اگر باشد همان برمیگردد. قاطی نشدنِ اصلِ سرمایه با داد و ستدِ روزمره، خواستهٔ صریحِ ویدئوی مرجع است. - شمارشِ دوره با
jAddMonthsانجام میشود، نه با تقسیمِ اختلافِ روز. ماهِ جلالی ۲۹ تا ۳۱ روز است و «سرِ برج» یعنی همان روز از ماهِ بعد، نه ۳۰ روز بعد.leaseElapsedتا سقفِ ۶۰۰ دوره جلو میرود تا حلقهٔ بیپایان ممکن نباشد. - مسیرِ «حواله هزینهها»ی ویدئو در این نسخه پیاده نشد — بردنِ اجاره به
state.expensesیعنی دو بار شمردنِ همان هزینه، چون ردیفِ کد ۹ از قبل در سود و زیان زیان ثبت کرده است. (در v32 بهصورتِ نمایشِ مشتق حل شد؛ پایینتر.) - ثبتهای جانبی:
leaseدرALL_VIEWSوTITLES؛#view-leaseو آیتمِ منو درadmin.html؛ بلوکِ.lz-*/.lzr-*درadmin.css(حالتِ قرمزِ.lz-warnعمداً پررنگ است — جابهجا شدنِ اصل خطایی است که تا ماهها دیده نمیشود). - تست:
node scripts/test-lease.js— ۱۰۲ بررسی در ۱۳ بخش؛ شاملِ بازسازیِ عددبهعددِ ویدئو (۹۹۵ / ۹٫۹۵۰ / ۱۰٫۰۸۴ / ۴۸۴٫۹۱۰)، ساختنِ عمدیِ سندِ غلط برای اثباتِ سقوطِ اصل به ۹۸۵٫۰۵۰، دوازده دورهٔ پشتسرهم، هر سه مسیرِ تسویه، کشفِ انحراف، و سه استثنای بالا.isAddRowبه فهرستِ استخراجِ هفت تستِ همسایه هم اضافه شد چونperfBucketOfوdocFlowرا مصرف میکنند.
#اجاره در مخارج (v32)
- این نسخه «روشِ دومِ» ویدئو را میسازد: در نرمافزارِ مرجع، اجارهٔ طلا بهصورتِ یک حوالهٔ وزنی داخلِ حسابِ «هزینهها» (کد ۱۴۰) با بابتِ «اجارهٔ طلا» مینشیند، تا اجاره کنارِ اجارهٔ مغازه و قبضِ برق و شارژِ پاساژ دیده شود. خواستهٔ واقعی این است: صاحبکار تصویرِ کاملِ مخارجِ برج را یکجا ببیند.
- ولی ثبتِ دوم ممنوع است — و این هستهٔ طراحیِ این نسخه است. مدلِ ما با مدلِ مرجع فرق دارد:
state.expensesیک آرایهٔ صرفاً ریالی است و حسابهای اجاره درstate.docsزندگی میکنند. اگر اجاره را بهstate.expensesهم میبردیم، همان مبلغ دو بار در سود و زیان مینشست: یک بار از مسیرِaddGoldو سطرِ «اضافه و اجارهٔ طلا» (که ردیفِ کد ۹ از قبل تولید میکند) و یک بار از مسیرِopex = expensesTotal(period). عددِ زیانِ نهایی دو برابرِ واقعیت میشد — خطایی که ماهها دیده نمیشود. - راهحل: نمایشِ مشتق، نه رکوردِ تازه.
leaseRentExpenses(period)هیچ دادهای نمیسازد؛ رویleaseList()میگردد،leaseDocs(l.id)را باز میکند و فقط ردیفهایی باr.lease.role === 'accrual'را کهdocInPeriodتأییدشان کند برمیدارد. شناسهٔ هر قلم'lz:' + docId + ':' + rowIndexاست تا یکتا و بازسازیشدنی باشد و هرگز باe.idِ واقعیِ مخارج قاطی نشود. مرتبسازی باjordنزولی است، همراستا با خودِ فهرستِ مخارج. - سه تابعِ کمکی روی همان یک منبع:
leaseRentExpenseW750(period)جمعِ وزنی،leaseRentExpenseRial(period)معادلِ ریالی باmarketRial()ِ امروز (نه نرخِ روزِ سند — عمدی است: این عدد برآوردِ «الان چقدر است»، نه بهای تمامشدهٔ تاریخی)، وleaseInExpenses(l)که باl.inExpenses !== falseپیشفرض را روشن میگذارد تا قراردادهای v31 بدون migration همین امروز در مخارج دیده شوند (§ قراردادها). - جدولِ مخارج ادغامی شد.
mergedقلمهای ریالی (t:'r') و طلاییِ مشتق (t:'g') را در یک آرایه میریزد و یکجا بر اساسِ تاریخ مرتب میکند، پس ترتیبِ زمانی از دو منبع میآید ولی کاربر یک فهرست میبیند. ردیفِ طلاییclass="exp-gold-row"و نشانِ.exp-dir.goldمیگیرد و دکمهٔ ویرایش/حذف ندارد — چون چیزی برای حذف وجود ندارد؛ منبعش سندِ اجاره است و ویرایش باید همانجا انجام شود. - کارتِ «تصویر کاملِ مخارج» با
.xf-gridسه عدد را کنار هم میگذارد: مخارجِ ریالی + اجارهٔ طلا = جمعِ هزینهٔ برج. زیرش.xf-noteصریح میگوید این جمع در سود و زیان دوباره شمرده نمیشود. این جمله در رابط ماند و به راهنما محدود نشد، چون دقیقاً همانجایی است که کاربر ممکن است اشتباه برداشت کند. گرید زیرِ ۷۸۰ پیکسل به یک ستون میریزد. - کلیدِ خاموشی در فرمِ قرارداد (
#lz_inx) رویl.inExpensesمینشیند و کارتِ قرارداد نشانِ.lz-inxمیگیرد. برای قراردادی که ماهیتِ سرمایهگذاری دارد و صاحبکار نمیخواهد در مخارجِ عملیاتی ببیندش. - ثبتهای جانبی: بلوکِ
.exp-gold-row/.exp-dir.gold/.exp-full/.xf-*/.lz-chk/.lz-inxدرadmin.css؛ لینکِdata-goleaseدر کارت که باgo('lease')به صفحهٔ اجاره میرود. - تست: بخشِ ۱۳ در
scripts/test-lease.js— ۲۰ بررسی. مهمترینهایشان منفیاند:expensesTotalبعد از اضافه شدنِ ماژول دقیقاً همان ۶۴٬۲۰۰٬۰۰۰ میماند وstate.expenses.lengthروی ۲ میماند (یعنی هیچ رکوردِ ساختگی ننشسته)؛ و تسویهٔ نقدی که دو سند میسازد، باز هم فقط یک قلمِ مخارج تولید میکند نه دو تا.
#گردشِ چک (v33)
- مسئله: تا اینجا چک فقط سه وضعیت داشت (
در جریان/پاس شده/برگشتی) و این برای چکِ شخصی کافی بود، چون چکِ خودت یا پاس میشود یا نمیشود. ولی چکِ دریافتی یک عمرِ میانی دارد که در هیچکدام از این سه نمیگنجید: خواباندهای، پولش نیامده، ولی دستت هم نیست. ویدئوی مرجع دقیقاً روی همین میایستد: «تا زمانی که این چک وصول نشده، موجودیاش را جدای از موجودی بانکی نگه میدارد.» CHK_STATESاز ۳ به ۶ رفت وCHK_CLOSED = ['پاس شده','نقد شده','خرج شده']اضافه شد.chkOpenدیگر «هرچه پاس نشده» نیست، بلکهCHK_CLOSED.indexOf(status) < 0است — وگرنه چکِ خرجشده تا ابد در کارتِ تعهدات میماند.در حسابتنها وضعیتِ میانی است و در CSS رنگِ آبیِ اختصاصی (.chk-st.wait) گرفت تا با سبزِ بستهشده و زردِ باز اشتباه نشود.chkDepositعمداً هیچ سندی نمیسازد. نرمافزارِ مرجع «در حساب» را یک ردیفِ با مبلغِ صفر داخلِ سندِ حسابِ بانکی ثبت میکند؛ در مدلِ ما چک خودش یک ردیفِ سند است، پس ردیفِ صفرِ اضافه فقط نویز میشد. قاعدهٔ ثابتِ برنامه این است: سند وقتی ساخته میشود که پول واقعاً جابهجا شده باشد. خواباندن پول جابهجا نمیکند؛ فقطe.depBankIdوe.depDateمینشیند و ردِ حسابرسی ازlogActionمیآید. تستِok('خواباندن هیچ سندی نمیسازد', ctx.state.docs.length, 1)همین را قفل میکند.- مانده و «در راهِ وصول» هرگز جمع نمیشوند.
chkBankPending(bankId, list)جمعِ چکهایدر حسابِ همان بانک را میدهد وRENDER.banksآن را در یک خطِ جداگانه (.bnk-chk) زیرِ مانده میگذارد، نه داخلش. اگر داخلِ مانده میرفت، یک چکِ برگشتی همهٔ گزارشهای نقدینگی را دروغ میکرد. ماندهٔ بانک باید همیشه یعنی «پولی که همین حالا خرجکردنی است». - یک باگِ قدیمی همینجا لو رفت:
chkSettleپول را بهe.bankIdمیریخت، ولیe.bankIdبرای چکِ دریافتی بانکِ صادرکننده است نه بانکِ ما. حالاdepBankIdاولویت دارد:var ba = (e.depBankId ? bankAccById(e.depBankId) : null) || (e.bankId ? bankAccById(e.bankId) : null). تست:ok('پول به حسابی رفت که چک آنجا خوابیده بود', setDoc.bankId, 'b-vanak'). chkUnsettleباید بداند به کجا برگردد. بازگردانیِ یک وصول نباید چک را بهدر جریانببرد — چک هنوز در باجهٔ بانک است. پس وضعیتِ مقصد از روی داده مشتق میشود:depBankId ? 'در حساب' : 'در جریان'. همین تابع سندِsettledIdوoutIdرا حذف و هزینههای دارایchkRefرا هم پاک میکند، تا سندِ یتیم نماند.- تنزیل یک هزینهٔ واقعی است، نه گرد کردن.
chkCashOut(e, cashId, net, dt)یک سندِ دریافت به اندازهٔnetمیسازد و اختلافِamount − netرا با شرحِ «تنزیل چک» درstate.expensesمینشاند (همان الگوی موجودِmeltFeeExpenseبا پیوندِchkRef). اگر ثبت نمیشد، سودِ آن ماه از واقعیت بهتر گزارش میشد. در مقابلchkSpendسندِ پرداخت به مبلغِ کاملِ چک میسازد؛ پشتنویسی تنزیل ندارد. - دکمهها از وضعیت مشتق میشوند، نه از یک منوی ثابت.
chkActsHtml(e)برای هر وضعیت فقط عملهای ممکن را میسازد (در حساب→ وصول/برگشت/برداشته شود؛در جریانِ دریافتی → خواباندن/نقد/خرج/برگشت؛در جریانِ شخصی → پاس/برگشت). این تابع عمداً ازRENDER.checkbookبیرون کشیده شد تا هم تست بتواند مستقیم صدایش بزند و هم جدول و تابلوهای یادآوری یک منبعِ واحد داشته باشند. - دو تابلوی یادآوری با یک
dueBox(cls, icoN, ttl, note, arr, act, actLbl)ساخته میشوند و ازchkCollectible(list, today)وchkAtBankDue(list, today)تغذیه میکنند — دو پرسشِ متفاوتاند: «سررسیدش رسیده و هنوز دستِ ماست» در برابر «خواباندهایم و امروز باید بنشیند». روی دستگاهِ لمسی@media (hover:none)دکمههای ردیف را همیشه نمایان میکند، چون hover وجود ندارد. - تابلوی کارها دو ردیفِ تجمیعی میگیرد، نه یک ردیف به ازای هر چک. ده چکِ قابلِ وصول یعنی ده هشدارِ هممعنا؛ تجمیع عمدی است تا تابلو قابلِ خواندن بماند.
- تست:
node scripts/test-check-book.js— ۲۶۳ بررسی. بخشِ ۱۴ توابعِ حالتگردان را با یک استخراجگرِ آکولاد-شمار (grabFn) از منبع بیرون میکشد و کلِ سناریوی ویدئو را بازسازی میکند (چکِ ۱٫۵ میلیاردیِ ارسلان قاسمی با سررسید ۱۴۰۲/۰۹/۳۰: خواباندن → وصول → بازگردانی بهدر حساب→ برگشت → نقد کردن با ۳۰ میلیون تنزیل → خرج کردن). بخشِ ۱۵ دکمهها، یادآوریها، پنجرهها، صفحهٔ بانک و تابلوی کارها را از متنِ منبع میسنجد.
#مادهٔ همراه و ترازِ وزنی (v34)
- مسئله: موتورِ سنگِ v28 برای نگین ساخته شده بود — هفت خانهٔ بههمبسته، حلکننده، قیراط، فیِ هر دانه. برای «چرم» همهٔ اینها مزاحماند: چرم یک نام دارد و یک مبلغ. کاربر مجبور بود روشِ «فقط مبلغ سنگ» را پیدا کند، پنج خانهٔ بیربط را نادیده بگیرد، و بعد روی فاکتور کلمهٔ «سنگ» ببیند در حالی که مشتری «چرم» میفهمد.
- ساختارِ دادهٔ موازی ساخته نشد. وسوسهای بود که
r.materialجدا تعریف شود؛ نشد. هر شاخهٔ جدید یعنی یک مسیرِ دوم درcomputeRowMag، در خروجیِ اکسل، در فاکتور، در کارتِ مالیات و در هر گزارش — و هرکدام یک جای فراموشکردنی. مادّه همانr.stoneاست با یک پرچمِmatr: true. نتیجه: صفر خطِ تغییر در محاسبات؛ فقط لایهٔ نمایش و فرم عوض شد. تستِhasnt('مادّه ساختارِ دادهٔ موازی نساخته', SRC, 'r.material =')همین را قفل میکند. - مادّه همیشه
mode: 'amount'است وsave()بقیهٔ خانههای نگین را عمداً صفر مینویسد (weight/each/qty/fi/grossWeight = 0). اگر کاربر اول نگین بزند و بعد به مادّه سوئیچ کند، بقایای قیراط و فی نباید در داده بماند — وگرنهstoneRialیک روز با دادهٔ نصفهکاره روبهرو میشود. stoneLbl(r)وdocStoneLbl(d)تنها نقاطِ تصمیمِ نامِ نمایشیاند. ردیف، فاکتورِ چاپی و کارتِ مالیات هر سه از همین دو تابع میخوانند.docStoneLblسه حالت دارد: فقط مادّه → نامِ خودشان با/، مادّه + نگین →سنگ و چرم، هیچ سنگی → رشتهٔ خالی. حالتِ چهارم (سندِ بیسنگ) اول از قلم افتاده بود وسنگ و نگینبرمیگرداند؛ چون همهٔ فراخوانها پشتِbd.stone ?بودند بیاثر ماند، ولی تست بیرونش کشید و درست شد.matrLedger(period)مشتق است، نه ذخیرهشده. مادّه ردیفِstate.inv.goodsنمیشود چون موجودیتِ مستقل نیست؛ روی ردیفِ طلا سوار است. پس ماندهٔ ریالی هر بار ازstate.docsساخته میشود و جهتِ ورود/خروج از همانrowMult(d, r)ِ همیشگی میآید — یعنی «مرجوع» و «تشخیصِ مطلق» خودبهخود درست حساب میشوند و هیچ منطقِ جهتِ دومی نوشته نشد.- آستانهٔ ۲٪ در
matrCostWarnعمدی است. معیار میانگینِ خریدِ همان مادّه (inAmt/inN) است. زیرِ ۲٪ اختلاف از گِرد کردن و چانهزنی میآید و هشدار دادنش فقط کاربر را به بیاعتنایی عادت میدهد. خروجیِnullیعنی «چیزی برای گفتن نیست»، نه «هشدار خاموش است». هشدار لحظهٔ ورود در فرم نشان داده میشود، چون بعد از ثبتِ سند دیگر کسی برنمیگردد نگاه کند. perfBalance(netW, market)جواب میدهد که این سود چقدر به مظنه بند است.perfReportحالا خالصِ وزنیِ دوره (netW += m * rowW750(r)) را هم جمع میزند. آستانهٔflatبرابرِ|netW| < 0.005گرم است — زیرِ آن، اختلاف از گِرد کردنِ اعشارِ ترازوست نه از بازبودنِ معامله.per1حساسیتِ ۱٪ مظنه است و عمداً بهجای یک عددِ خام، هر دو جهت (بالا و پایین) با برچسبِ سود/زیان نشان داده میشود.- چرا این جعبه لازم بود: ۵۰۰ گرمِ ۷۵۰ در مظنهٔ ۸۲٫۶۷ فروخته و نخریده = ۱۱۵٫۴۲۵۵ مثقالِ ۷۰۵. (مثقالِ فیزیکی ۴٫۶۰۸۳ گرم است، ولی چون وزنها به عیارِ ۷۵۰ نگه داشته میشوند مقسومٌعلیهِ درست ۴٫۶۰۸۳ × ۷۰۵ ÷ ۷۵۰ = ۴٫۳۳۱۸ است — همان
GRAM18_DIVISOR.) همان دوره در مظنهٔ ۸۲٫۶۷ «زیانِ ۸٬۰۷۹٬۷۷۸» است و در مظنهٔ ۱۰۰ «سودِ ۱۹٬۶۲۲٬۳۱۹» — بدونِ آنکه یک سند عوض شده باشد.rowDayProfitاز قبل درست حساب میکرد؛ چیزی که کم بود، گفتنِ ناپایداریِ عدد به کاربر بود. - تست:
node scripts/test-stone.js— ۱۶۲ بررسی (بخشِ ۱۰ مخصوصِ v34). سناریوی ۵ بند چرمِ ۱۱۰٬۰۰۰ ﷼ بازسازی میشود تا ماندهٔ ۵۵۰٬۰۰۰ → ۴۴۰٬۰۰۰ قفل شود، وnear('چرم به گرمِ ۷۵۰ اضافه نمیشود', c.w750, 1)تضمین میکند مادّه هیچوقت وزن نشود.perfBalanceهم بهscripts/test-perf.jsاضافه شد.
#دفتر روزانهٔ سود و پنجرهٔ فرمول (v35)
- مسئله: «کارکرد» یک عددِ درشت میداد — سودِ کلِ دوره — و کاربر هیچ راهی نداشت بفهمد آن عدد از کدام روز آمده. ویدئوی مرجع دقیقاً روی همین میایستد: یک صفرِ جاافتاده در فیِ فروش (۸۱۸٬۴۰۰ بهجای ۸۱٬۸۴۰٬۰۰۰) روی ۱۰۰ گرم، ۱٬۸۸۰٬۳۷۵٬۹۱۶ ریال زیانِ خیالی میسازد و کلِ گزارشِ ماه را وارونه میکند. تا وقتی سود فقط یک جمعِ کل باشد، این اشتباه دیدنی نیست. راهِ حل «گزارشِ دقیقتر» نبود، قابلِ ردیابی کردنِ همان گزارش بود.
- ساختارِ دادهٔ موازی ساخته نشد و فرمولِ سود بازنویسی نشد.
dpReport(period, subject)روی همانstate.docsمیچرخد، همانperfBucketOfرا برای دروازهبانی و همانrowMult(d, r)را برای جهت صدا میزند، و سودِ هر ردیف را از همانrowDayProfit(d, r, market)ِ موجود میگیرد. اگر فرمولِ دومی نوشته میشد، روزی میرسید که جمعِ این جدول با «کارکرد» یکی نباشد و کاربر بین دو عددِ رسمی گیر کند. تست همین را قفل میکند:near('جمعِ سودِ دفتر روزانه با کارکرد یکی است', dp.total.profit, perf.tradeNet). - کلیدِ منظر (
dpSubject) بهجای دو جدولِ جدا. طلا و سکه واحدِ ناهمجنس دارند (گرمِ ۷۵۰ در برابر عدد) و جمعزدنشان در یک ستون بیمعناست. ولی دو جدولِ همیشهباز هم صفحه را شلوغ میکرد. پس یکseg-toggleگذاشته شد که «فقط طلا» و هر نوع سکهای که در همان دوره واقعاً معامله شده را نشان میدهد (dpSubjects(period)) — نه فهرستِ ثابتِ همهٔ سکهها. با سوئیچ به سکه، مقدارِ هر ستون ازrowW750بهnum(r.tedad)و نرخِ مرجع از مظنه بهcoinDayRial(coinName, market)میرود. - قاعدهٔ هشدار عمداً به گردشِ مالی بند نیست. اولین ایده «سودِ بزرگ نسبت به گردش» بود و کنار گذاشته شد: در دورههای
allوyearهر ردیف با مظنهٔ امروز سنجیده میشود، پس رشدِ طبیعیِ قیمتِ طلا در یک سالِ گذشته خودش نسبتِ بزرگ میسازد و جدول پر از هشدارِ دروغ میشد. دو قاعدهٔ جایگزین مستقل از زماناند: (۱) هر ردیفِ بدون فی، چون سودِ آن روز قطعاً ناقص است؛ (۲) فیِ بیشینه/کمینهٔ روز بیرون از بازهٔ سهبرابرِ میانهٔ همان دوره (DP_BAND = 3). میانه انتخاب شد نه میانگین، چون خودِ عددِ پرت میانگین را با خودش میبرد و آنگاه دیگر مرجعِ سالمی نمیماند —ok('میانه به عددِ پرت نمیلغزد', dpMedian([80,81,82,83,8100000]), 82). - چرا ضریبِ ۳؟ نوسانِ واقعیِ بازار در یک دوره حتی چند ماهه از دو برابر رد نمیشود، ولی جاافتادنِ یک رقم همیشه ضریبِ ۱۰ میسازد. سه، فاصلهٔ امنی است که نوسانِ سالم را عبور میدهد و اشتباهِ تایپی را نگه میدارد. تستِ ده روزِ ۶۰م→۱۰۰م هیچ پرچمی نمیگیرد، ولی سناریوی ویدئو میگیرد.
fxModal/fxStepsHtmlعمداً عمومی نوشته شدند، نه مخصوصِ این جدول. پیامِ مشترکِ هر دو ویدئو یک چیز است: هر عددِ محاسبهشده باید با مقادیرِ واقعی باز شود. پس اجزای پنجره (fxm-step/fxm-eq/fxm-part/fxm-op/fxm-res/fxm-chain) هیچ ارجاعی به سود ندارند وdpFxSteps(x, R)فقط یکی از تأمینکنندههای آن است. جمعِ فاکتور و هر عددِ مشتقِ بعدی میتوانند بدونِ کپیِ CSS از همین استفاده کنند.- گامِ اجرت جدا و شرطی است. فقط وقتی
|wage| >= 1نمایش داده میشود. گامِ همیشگیِ «اجرت = ۰» کاری نمیکند جز اینکه چشمِ کاربر یاد بگیرد گامها را نخواند. - درِ خروجِ جدول به «دفتر روزانه» است، نه به یک صفحهٔ تازه. کلیک روی تاریخ
DB.preset = 'manual'وDB.from = DB.to = dateمیگذارد وgo('daybook')میکند. صفحهٔ ریزِ اسناد از قبل وجود داشت و کامل بود؛ ساختنِ نمای دومِ «اسنادِ این روز» یعنی دو جای نگهداری برای یک چیز. مسیرِ «سودِ مشکوک → سندهای همان روز → اصلاح → رفرش» با دو کلیک بسته میشود. - ردیفِ جمعِ دوره در
tfootاست نه یک کارتِ جدا، تا با اسکرول همراه ستونها بماند و کاربر بتواند مستقیم بالای هر ستون جمعش را ببیند. میانگینهای فوتر وزنیاند (buyAmt/buyQty)، نه میانگینِ میانگینهای روزانه؛ وگرنه یک روزِ تکردیفه بهاندازهٔ یک روزِ پرمعامله در میانگینِ دوره وزن میگرفت. - ثبتهای جانبی:
dpSectionHtmlبعد ازperfSectionHtmlدرRENDER.reportsوdpBind(reportPeriod)کنارِ بایندِ[data-rp]؛ بلوکِ.dp-panel/.dp-subs/.dp-tbl/.dp-date/.dp-amt/.dp-bad/.dp-why/.fxm*درadmin.cssبا نسخهٔ تیره و شکستِ زیرِ ۶۲۰ پیکسل. - تست:
node scripts/test-dayprofit.js— ۶۷ بررسی در ۱۱ بخش. مهمترینشان بازسازیِ کاملِ سناریوی ویدئوست (فیِ ۸۱۸٬۴۰۰ روی ۱۰۰ گرم → پرچمِ قرمز → اصلاح به ۸۱٬۸۴۰٬۰۰۰ → برگشتِ سود)، بهعلاوهٔ بررسیهای منفی: هیچ ردیفِ خارج از دروازهٔperfBucketOfوارد جدول نمیشود و نوسانِ سالمِ بازار پرچم نمیگیرد.
#بستن سال مالی و دفترهای حسابداری (v36)
- مسئله (از دو ویدئوی مرجع، که در واقع یک موضوعاند): ویدئوی اول «بستن سال مالی» را یاد میدهد — آخرِ سال دفتر بسته و بایگانی میشود و دفترِ نو با همان ماندهها باز میشود، چون تعدادِ اسنادِ یک سال از حد میگذرد، شمارهٔ فاکتور باید از یک شروع شود و گزارشها باید «امسال» را نشان بدهند نه ده سالِ روی هم. ویدئوی دوم عارضهٔ همان کار است: چکی که پارسال از کسی گرفتهای و امسال برگشت میخورَد، در فهرستِ چکهای آن شخص پیدا نمیشود. علتش را خودِ ویدئو لو میدهد: نرمافزارِ مرجع چکِ منتقلشده را زیرِ یک حسابِ داخلی به نامِ «موجودی ابتدای دوره» میبرد و نامِ صاحبش فقط در فیلدِ یادداشت باقی میماند — «یعنی کیمیا نمیداند که از ایشان گرفتیم.» راهی که ویدئو یاد میدهد یک دور زدن است: بهجای «پرداخت مرجوعی» بزن «پرداخت» و چک را دستی از فهرستِ چکهای موجود پیدا کن.
- ما دور زدن را پیاده نکردیم، علتش را پیاده کردیم. قاعدهٔ کلی: هر چیزِ زنده با صاحبِ خودش منتقل میشود. این تصمیم از یک مشاهده در کدِ خودمان آمد، نه از سلیقه:
chkList()،instSchedule()وrepJob()هر سه ازstate.docsمیخوانند و صاحبشان را ازd.personId/d.personNameمیگیرند. یعنی اگر سند منتقل نشود، خودِ چک و قسط و امانت هم منتقل نمیشوند — دقیقاً همان حفرهای که ویدئوی دوم نشانش میدهد، در کدِ ما هم بالقوه وجود داشت. حالا چکِ باز در دفتر جدید هم زیرِ سندِ همان شخص مینشیند، پسchkList()صاحبش را میشناسد و «برگرداندن چک» بدون هیچ ترفندی کار میکند. تست همین را قفل میکند:ok('و صاحبش را میشناسد', nc[0].person, 'کیمیا')در کنارِok('«موجودی ابتدای دوره» صاحبِ چک نیست', …, false). - مانده با
openingRowsمنتقل میشود، نه با سندِ ساختگیِ «مانده قبلی». ساختنِ یک سندِ افتتاحیه سادهتر بود، ولی آن سند بعداً همهجا ظاهر میشد: در کارکرد، در دفتر روزانهٔ سود (v35)، در مالیات و در کاردکس. ماندهٔ پارسال معامله نیست، عددِ شروع است؛ پس در همان جایی مینشیند که برنامه از قبل برای عددِ شروع دارد.ycPlanدقیقاً همان کاهشی را میزند که فرمِ «شخص» میزند (openGold/openRial/openCoinsدر کنارِopeningRows)، تا نتیجه با چیزی که کاربر دستی وارد میکرد یکی باشد. - قاعدهٔ سندِ زنده.
ycAliveWhy(d, ctx)تنها جایی است که تصمیم میگیرد یک سند بیاید یا نه، و چهار شاخه بیشتر ندارد — هر کدام یک تعهدِ باز: «چکِ باز» (ycOpenChecks()= هر چکی که وضعیتش درCHK_CLOSEDنیست)، «قسطِ ناتمام» (instSchedule(s).openCount > 0)، «پرداختِ قسطِ ناتمام» (instIsPayDoc(d)که به همان فروش اشاره کند، وگرنه جدولِ قسط در دفتر جدید پرداختهای قبلی را نمیبیند و مانده را دوباره طلب میکند) و «امانتِ نزد تعمیرکار» (repIsDoc(d) && !repJob(d).done). سندِ منتقلشدهcarry: trueوcarryWhyمیگیرد تا بعداً هم بشود پرسید چرا اینجاست. ماندهٔ اول دوره = ماندهٔ پایانی − اثرِ سندهای منتقلشده. این تفریق هستهٔ درستیِ کلِ ماژول است. بدون آن ماندهٔ هر شخصی که چکِ باز یا قسطِ ناتمام دارد دو بار شمرده میشد: یکبار درopeningRowsو یکبار در سندِ زندهای که دوباره آمده. با آن،openingRows + اسنادِ منتقلشدههمیشه دقیقاً برابرِ ماندهٔ پایانِ دفتر قبلی است. تست این اتحاد را روی دفترِ ساختهشدهٔ واقعی میسنجد، نه روی نقشه:near('اتحاد با سندِ منتقلشده — ریالِ کیمیا', opened2.p1.rial, closing2.p1.rial, 1).- سندِ منتقلشده واردِ کارکرد نمیشود —
if (ycIsCarryDoc(d)) return null;درperfBucketOf، دقیقاً کنارِ همان دو نگهبانِ قبلی (hdgIsSettleDocاز v17 وrepIsCustodyاز v16) و به همان دلیلِ خانوادگی: چیزی که معامله نیست نباید سود بسازد. معاملهٔ آن چک پارسال انجام شده و سودش همانجا شمرده شده؛ اگر دوباره وارد شود، سودِ پارسال یک بار دیگر در امسال ظاهر میشود و «دفتر روزانهٔ سود» روزِ اولِ سال را با یک قلهٔ ساختگی نشان میدهد. - رأس با یک ردیف حفظ میشود، نه با چند ردیف. ویدئو برای نگهداشتنِ سنِ حساب، مانده را به چند ردیف با تاریخهای اصلی میشکند.
ycRaas(items)بهجایش تاریخِ رأس (میانگینِ وزنیِ تاریخها) را حساب میکند و یک ردیف میگذارد. رأس در تعریف یعنی «تاریخِ معادلِ واحد»، پس نتیجه از نظرِ سنسنجی یکسان است و ردیفها چند برابر نمیشوند. پیادهسازی ازjDayوjBackِ موجود استفاده میکند و علامتِ وزن را قدرمطلق میگیرد (بدهکار و بستانکار هر دو سن دارند). - ارز عمداً در
openRialجمع میشود.balances()هیچ راهی برای پر کردنِ محورِcursاز ماندهٔ اول دوره ندارد و فرمِ «شخص» هم از قبل ردیفِ ارزی را درopenRialجمع میزند. پس اگر اینجا جمع نمیشد، ماندهٔ ارزیِ طرف حساب موقعِ بستنِ سال بیصدا بخار میشد. ردیفِkind:'currency'برای دیدن درopeningRowsمیماند و عددش برای شمردن درopenRialمیرود — همان چیزی که اگر کاربر دستی همین ردیف را وارد میکرد هم رخ میداد. - بایگانی زیر کلیدِ جداگانه، نه داخلِ دفترِ جاری.
ycCloseیک snapshot کامل را باPOST {key:'book:'+id}میفرستد. اگر بایگانی داخلِstateمینشست، هر ذخیرهٔ روزمره کلِ سالهای گذشته را دوباره مینوشت و فایل بیدلیل بزرگ و شکننده میشد.state.booksفقط یک فهرستِ سبک است (ycIndexOf: نام، تاریخ، تعدادِ سند و طرف حساب) و خودِ دفتر جای دیگری است. این کار بدون هیچ تغییری در سرور ممکن بود، چون/api/admin-storeاز اول یک انبارِ عمومیِ کلید/مقدار است. - قفل روی
persist()است، نه روی صدها نقطهٔ نوشتن. وقتی کاربر دفترِ بایگانی را برای تماشا باز میکند،stateحاوی دادهٔ همان سالِ بسته است؛ یک ذخیرهٔ اتفاقی یعنی پاکشدنِ دفترِ جاری با دادهٔ پارسال.persist()تنها دروازهٔ نوشتن در کلِ برنامه است، پسif (bookLocked()) return;در سطرِ اولش جای گذاشتنِ نگهبان در تکتکِ فرمها را میگیرد و هیچ مسیری از قلم نمیافتد. - آستانههای گردوخاک، با اعدادِ خودِ ویدئو:
YC_DEF = { minInvG: 0.3, minBalG: 0.3, minBalR: 999999 }. اینها برای تهحساباند: اختلافِ ترازو و چند ریالِ باقیمانده که نمیارزد سالِ جدید با آن شروع شود. هر سه در پنجره قابلِ تغییرند و صفر یعنی هیچچیز حذف نشود؛ آنچه حذف میشود درplan.drop/plan.invDropشمرده و در پیشنمایش نشان داده میشود، چون حذفِ بیاعلام همان بلایی است که کاربر ماهها بعد کشفش میکند. - پیشنمایش و اجرا از یک تابع میآیند.
ycPlan(o)خالص است و چیزی را عوض نمیکند؛ همان نقشهای که در پنجره نشان داده میشود همانی است کهycBuild(plan)اجرا میکند. اگر دو مسیرِ جدا میداشتند، روزی میرسید که پیشنمایش یک چیز بگوید و انتقال چیزِ دیگری بکند — و این تنها کارِ برنامه است که برگشتناپذیر است. - هشدارهای پیش از بستن (
ycPreflight) دکمهاند، نه متن. چهار موردِ «آبشدهٔ شرطیِ تعیینتکلیفنشده»، «قسطِ سررسیدگذشته»، «چکِ سررسیدگذشتهٔ باز» و «کارِ بازِ تعمیر» هر کدامviewدارند و کلیک روی هرکدام پنجره را میبندد و کاربر را همانجا میبرد. هیچکدام مانع بستن نیستند (همهشان با سندشان منتقل میشوند و چیزی گم نمیشود)، ولی هر چهار مورد دلیلِ خودشان را در متن دارند. - طراحی: پنجرهٔ بستن دو ستونِ «منتقل میشود / منتقل نمیشود» را کنارِ هم میگذارد (
.yc-prev، سبز و قرمز) و با هر تغییرِ آستانه زنده بهروز میشود، چون کاربر باید هر دو طرفِ تصمیم را همزمان ببیند. دفترِ بایگانیِ بازشده یک نوارِ.yc-lockمیگیرد که از دور پیداست و دکمهٔ «بازگشت به دفتر جاری» دارد. رنگ عمداً طلایی است نه قرمز: قرمز باعث میشود کاربر از رویش رد شود. - ثبتهای جانبی:
book/booksدرdefaults؛['books', 'دفترهای حسابداری']درALL_VIEWSو درTITLES؛#view-booksو لینکِ منو درadmin.html؛ بلوکِ.yc-*/.bk-*درadmin.cssبا نسخهٔ تیره و شکستِ زیرِ ۷۶۰ پیکسل. - تست:
node scripts/test-yearclose.js— ۱۰۵ بررسی در ۱۳ بخش. مهمترینشان بازسازیِ کاملِ سناریوی ویدئوی دوم است (چکِ بازِ کیمیا از دفتر قبلی میآید و صاحبش را نگه میدارد)، بهعلاوهٔ اتحادِ مانده روی دفترِ واقعاً ساختهشده، بقای قسط و امانتِ تعمیر، و بررسیهای منفی: سندِ چکِ بسته منتقل نمیشود و سندِ منتقلشده ازperfBucketOfبیرون میمانَد.
#چند دفترِ موازی و راهاندازیِ گامبهگام (v37)
- مسئله (از ویدئوی مرجع): هر چه تا امروز وارد شده «تستی» بوده و حالا باید دفترِ واقعی ساخته شود. ویدئو سه چیز را یاد میدهد: ساختِ دفترِ نو از «لیست دفترها» بدون هیچ محدودیتی در تعداد، سوئیچِ رفتوبرگشتی بین دفترها از روی نامِ کسبوکار در نوارِ بالا، و ویزاردِ گامبهگامی که برای دفترِ نو دوباره ظاهر میشود («انگار تازه کیمیا را دریافت کردهاید»). سؤالِ کلیدیِ آخرِ ویدئو هم هست: «اشخاص و اجناسِ دفتر قبلی منتقل میشوند؟» و پاسخِ صریحش: «اصلاً این امکانش وجود ندارد، دنبالش هم نگردید.»
- مدلِ v36 را گسترش دادیم، مدلِ دومی نساختیم. وسوسه این بود که «دفترهای موازی» یک ساختارِ تازه بگیرند و «دفترهای بایگانی» همان v36 بمانند. ولی کلِ ماشینِ v36 روی سه چیز سوار است:
state.book(هویتِ دفترِ باز)،state.books(فهرستِ سبک) وbook:<id>(خودِ عکسِ دفتر) — و دفترِ موازی دقیقاً همین سه را میخواهد، با یک تفاوت:archivedنیست. مدلِ دوم یعنی دو منبعِ حقیقت برای «فهرستِ دفترها»، و آن روزی که این دو از هم میپاشند کاربر یک دفترش را گم میکند. حالاbkAll()تنها جایی است که فهرست ساخته میشود و بایگانی و موازی فقط دو حالتِ یک ردیفاند. - انتقال بین دفترها عمداً وجود ندارد. این «هنوز پیاده نشده» نیست؛ تصمیم است، طبقِ ویدئو. دلیلِ فنیاش هم همان است که v36 نشان داد: هر ردیف با شناسههای داخلیِ همان دفتر گره خورده (
personIdروی سند،fromMeltروی جنس،presetروی گروهِ دسترسی). کپیِ نیمهکارهٔ «فقط اشخاص و اجناس» یعنی دفتری که ماندههایش با اسنادش نمیخوانَد — بدتر از نداشتن. راهی که ویدئو پیشنهاد میکند و ما هم در متنِ برنامه گذاشتهایم: همان دفترِ تستی را نگه دار، «تستی» را از نامش بردار و ورودیهایش را اصلاح کن. - یکتاییِ نام با
bkKey()نرمالسازی میشود، نه با مقایسهٔ خام. ویدئو میگوید نامِ تکراری رد میشود؛ ولی «گالری کیمیا» با «گالري كيميا» (یِ عربی و کافِ عربی) دو رشتهٔ متفاوتاند و در عمل یک ناماند.bkKeyیِ/کِ عربی را یکسان میکند، نیمفاصله و نشانههای جهتِ نامرئی را به فاصله تبدیل میکند، فاصلههای تکراری را جمع میبندد و trim/lowercase میکند. بدون این، کاربر دو دفترِ همنام میسازد و بعد در سوئیچر نمیفهمد کدام کدام است — و این خطا از آنهاست که ماهها بعد کشف میشود. bkSwitchاول ذخیره میکند، بعد بار میکند. ترتیب اتفاقی نیست: اگر اول مقصد بار شود و بعد ذخیره، هر خطای شبکه در وسطِ کار یعنی دفترِ مبدأ روی'app'بازنویسیشده با دفترِ مقصد. با ترتیبِ فعلی، بدترین حالت این است که سوئیچ انجام نشود و کاربر همانجا بماند.- نگهبانِ
bookLocked()روی سوئیچ و ساخت — این یک حفرهٔ واقعیِ از دست رفتنِ داده را بست. وقتی دفترِ بایگانی باز است،stateدفترِ بایگانی است ولی کلیدِ'app'هنوز دفترِ زندهٔ کاربر را دارد. اگر از همانجا سوئیچ یا ساختِ دفتر مجاز بود،persist()دفترِ مقصد را روی'app'مینوشت و دفترِ زنده — که هرگز زیر کلیدِ خودش بایگانی نشده بود — برای همیشه میرفت. حالا هر دو تابع در همان سطرِ اولif (bookLocked())میزنند. تستِ بخشِ ۱۱ دقیقاً همین را قفل میکند: بعد از تلاشِ ناموفق،STORE.appهنوز دفترِ زنده با همان تعدادِ سند است. ycBuildیک باگِ v36 داشت که همینجا اصلاح شد:isDefaultبه دفترِ نو منتقل نمیشد. یعنی بعد از بستنِ سال، پرچمِ پیشفرض روی دفترِ بایگانی و قفلشده میماند و برنامه دفعهٔ بعد داخلِ یک دفترِ فقطخواندنی باز میشد؛ کاربر تایپ میکرد و خیال میکرد ذخیره نمیشود. تا وقتی پیشفرض معنای اجرایی نداشت این باگ دیده نمیشد.- معنیِ چهار فیلدِ تازه.
codeعددِ کوتاهِ گفتاری است (کاربر میگوید «دفتر ۲»، نه بیست کاراکتر GUID) و ازbkNextCode()= بیشینه+۱ میآید.jobفقط برچسب نیست:bkJobGroups()از روی آنcatalog.personGroupsدفترِ نو را ازPERM_PRESETSِ موجود پُر میکند — یعنی اولین کاری که کاربرِ تازه بهتنهایی از پسش برنمیآید.visibleدفترهای کمکاربرد را به تبِ «مخفی» میبرد بدون حذف.isDefaultیعنی «دفتری که برنامه با آن بالا میآید» و باbkBoot()بینِloadStateوloginGateواقعاً اجرا میشود؛ خطاهایش عمداً بلعیده میشوند تا نبودِ یک عکسِ دفتر کلِ برنامه را نخواباند. bookMeta()فیلدهای نبوده را پُر میکند. دفترِ ساختهشده پیش از v37 نهcodeدارد نهvisible؛ و چونvisibleبرابرِundefinedاست، در تبِ «جاری» پیدا نمیشود — کاربر دفترِ اصلیِ خودش را در فهرست نمیبیند. یک normalizeِ کوچک در همان تابعی که همه از آن میخوانند، جای یک migrationِ جداگانه را میگیرد.- ویزارد به صفحههای واقعی مسیر میدهد، فرمِ تازه نمیسازد. حینِ کار کشف شد که همهٔ صفحههای «موجودی ابتدای دوره» از قبل هستند (
INV_TABS: نقدی و ارزی، سکه بانکی، چک، آبشده، اجناس) و اولینشان حتی همان عنوانِ ویدئو را دارد. فرمِ سبکِ داخلِ ویزارد همیشه چند فیلد کم دارد (بارکد، عکس، فی، عیار) و دو مسیرِ ورود برای یک جدول یعنی دو جای اعتبارسنجی که روزی از هم جدا میشوند. پسWZ_STEPSفقطviewوtabنگه میدارد و کاربر را به همان صفحهٔ کامل میبرد. - «انجامشده» از دادهٔ واقعی مشتق میشود، نه از تیکِ ذخیرهشده. هر زیرگام یک
n()دارد که تعدادِ ردیفهای واقعی را میشمارد. اگر تیک ذخیره میشد، کاربری که ردیفهایش را پاک میکند همچنان گامِ سبز میدید. تنها چیزی که ذخیره میشود صرفنظرِ عمدی است، چون ویدئو صریح میگوید «اگر الآن هیچی موجود ندارید، این مرحله را بیخیال شوید» — و صرفنظر را نمیشود از داده حدس زد. - صفحهٔ
setupعمداً درALL_VIEWSنیست. اگر بود، در منو ظاهر میشد (در حالی که یکبارمصرف است) و یک تیکِ دسترسیِ بیمعنا هم به فرمِ کاربران اضافه میکرد.canViewبرایش مثلِdocاستثنا دارد و در بوت فقط وقتی خودکار باز میشود که هیچ سندی ثبت نشده باشد — وگرنه دفترِ فعالِ کسی هر روز با صفحهٔ راهاندازی سلام میکرد. - کدِ دفتر بهجای عکسِ دفتر. ویدئو ستونِ «عکس» دارد؛ ما نشانِ کد گذاشتیم. کاربرها با کد حرف میزنند، و آپلودِ تصویر برای هر دفتر یک گامِ اضافه و حجمِ اضافه است. ستونِ
IDهم شناسهٔ کامل را درtitleنگه میدارد ولی کوتاهشده نشان میدهد؛ برای پشتیبانی لازم است، ولی بیست کاراکترِ خام جدول را نابود میکند. - رنگِ یادآورِ ویزارد آبی است نه طلایی: «کارِ باقیمانده» است، نه هشدار؛ طلایی در این برنامه معنیِ «مراقب باش» دارد.
- یک باگِ قدیمی هم سرِ راه اصلاح شد: کلاسِ
ce(وسطچین) در پنج جایadmin.jsاستفاده میشد ولی هیچ قاعدهای در CSS نداشت؛ قاعدهاش در بلوکِ v37 اضافه شد. - ثبتهای جانبی:
bkChipدر نوارِ بالایadmin.htmlو#view-setup؛books/setupدرTITLES؛bkChipSync()درshowViewتا نامِ دفتر هرگز کهنه نمانَد؛ بلوکِ.bk-*/.wz-*درadmin.cssبا نسخهٔ تیره و شکستِ زیرِ ۹۰۰ پیکسل؛ برچسبِ کشv=20260813d. - تست:
node scripts/test-books.js— ۱۷۳ بررسی در ۱۵ بخش، با شبیهسازیِ درونحافظهایِfetchتا چرخهٔ واقعیِ ذخیره/بارگذاری اجرا شود. مهمترینشان رفتوبرگشتِ کاملِ A→B→A→B است (هر دفتر دادههای خودش را دستنخورده پس میدهد)، نگهبانِ دفترِ قفل که'app'را نجات میدهد، حملههای یکتاییِ نام با یِ/کِ عربی و نیمفاصله، و بررسیهای منفی: دفترِ نو واقعاً خالی است و دفترِ باز حذف نمیشود.
#کارکرد اجناس — پای خودت (v38)
گزارشِ دومِ سود، با مبنای فیِ دریافتی بهجای نرخِ روز. توابعش با پیشوندِ gp در admin.js جمعاند و از RENDER.reports بلافاصله بعد از perfSectionHtml سوار میشوند.
- چرا گزارشِ تازه، و چرا کارکردِ موجود عوض نشد.
perfReport(v6) هر معامله را با نرخ روز میسنجد و به این سؤال جواب میدهد: «از بازار جلو زدم؟» ویدئوی مرجع سؤالِ دیگری میپرسد: «روی جنسی که خودم با ٪۱۰ آوردهام، چقدر گرفتم؟» — سؤالی که جوابش به مظنه اصلاً بند نیست. اگر این دو در یک عدد ادغام میشدند، حاصل یک عددِ دورگه بود که به هیچکدام جواب نمیداد. پس دو گزارش کنارِ هم مینشینند و هرکدام مبنایش را در نشانِ هدرش اعلام میکند. - فرمولِ واحد.
سود طلا = جهت × وزن۷۵۰ × (درصدِ ردیف − درصدِ دریافتی) ÷ ۱۰۰کهجهت = -rowMult(d, r). همین یک عبارت هر پنج ردیفِ جدولِ ویدئو را توضیح میدهد؛ مرجوعی شاخهٔ جداگانه ندارد چونrowMultاز قبل علامتش را برمیگرداند — همان مکانیزمی که v20 برای مبالغ استفاده کرده بود. ستونِ ریال جداست:جهت × [وزن۷۵۰ × (فی − فیِ دریافتی) + اجرتِ ریالی]. - چرا
perfBucketOfرا صدا نمیزند (و این تنها جایی است که دو گزارش عمداً همجامعه نیستند): آن تابع اسنادِ «دریافت» و «پرداخت» را کنار میگذارد (v17) و با مبنای نرخِ روز کاملاً حق دارد، چون طلایی که بابتِ تسویه جابهجا میشود فیِ روز ندارد. ولی اولین درسِ ویدئو دقیقاً روی همین دو سند میافتد: پرداختِ ۲۰ گرم با ٪۱۵ در برابرِ پایِ ٪۱۰ سودِ ۱ گرم است. با آن دروازه، این گزارش خالی میماند. پسgpRowOkاستثناهایی را که به مبنا ربطی ندارند تکرار میکند (ycIsCarryDoc،repIsCustody، و از مسیرِstkRowSubjهم کد ۹ و ردیفِ کاغذیِ قسط) و فقط استثنای مبنامحور را نمیآورد. - پایه از دو منبع میآید و هر دو لازماند:
state.inv.goods(موجودیِ ابتدای دوره، با تبدیلِ عیار به ۷۵۰) و ردیفهای ورودیِ اسناد، هر دو با میانگینِ وزنی. بدونِ اولی جنسِ افتتاحیه پایهٔ صفر میگرفت و هر فروشش سودِ کامل نشان میداد؛ بدونِ دومی جنسی که امروز خریدهای اصلاً پایه نداشت. - برگشتی پایه نمیسازد — این یک باگِ واقعی بود که تست گرفتش. در پیادهسازیِ اول هر ردیفِ ورودی واردِ میانگین میشد، از جمله «دریافت مرجوعی». نتیجه: پای خودت در بازسازیِ جدولِ ویدئو بهجای ٪۱۰ میشد ٪۱۱٫۸۲ و جمعِ نهایی ۱٫۸۱− بهجای ۱٫۴۴−. منطقش هم روشن است: جنسِ مرجوعی با همان قیمتی برمیگردد که با آن رفته بود و خریدِ تازهای رخ نداده؛ اگر واردِ میانگین شود، برگشتی بهجای خنثیکردنِ ردیفِ اصلی، آیندهٔ گزارش را هم خراب میکند.
- چرا
gpBasisدوره را فیلتر نمیکند: هر چهار بازهٔ گزارش به امروز ختم میشوند، پس ردیفِ ورودیای بعد از پایانِ بازه وجود ندارد که پایه را آلوده کند. جنسی که پارسال خریده شده باید پایهٔ فروشِ امسال باشد. اگر روزی بازهٔ تاریخیِ دلخواه اضافه شد، برش باید همینجا بخورد. - اجرتِ درصدی در ستونِ ریال صفر است (
gpWageRial) چون قبلاً در ستونِ طلا شمرده شده؛ وگرنه دوبارهشماری میشد. و همین قاعده است که درسِ آخرِ ویدئو را قابلِ تست میکند: بخشِ ۴ تست همان فروش را دو بار اجرا میکند — یکبار با ٪۱۰ و یکبار با اجرتِ ریالیِ همارز — و میسنجد کهgoldNetمیشود ۲−،rialNetهمانقدر بالا میرود، وtotalGoldدر هر دو حالت یکی است. - مالیات در جمع میآید (
docTaxBreakdown): تا وقتی پرداخت نشده، پولش دستِ شماست و در حسابوکتاب سود است. جمعِ نهاییtotalGold = goldNet + rialNet ÷ قیمت گرم۷۵۰است و اگر نرخ نباشد، تبدیل انجام نمیشود وnoMarketاعلام میشود — عددِ ساختگی ساخته نمیشود. - ردیفِ بیپایه پنهان نمیشود، پرچم میخورد. قلمی که نه در انبار آمده و نه سندِ ورودی دارد،
hasBasis:falseمیگیرد، با.gp-nbکمرنگ میشود و تعدادش زیرِ جدول با اشاره به «موجودی اجناس» اعلام میشود. حذفش یعنی جمع با خلاصه وضعیت نمیخواند و کاربر دلیلش را نمیفهمد. - طراحی: هر برچسب یک کارت با زبانهٔ رنگی (
.gp-card/.gp-tab)، جفتها کنارِ هم از رویGP_PAIRچون ویدئو اصرار دارد این دو را «با هم» ببینید، تولتیپِfx()روی هر عدد با فرمولِ خودش، و جمعبندیِ سهستونه. پسزمینهٔ ردیفِ جمع عمداً--blue-softاست نه--navy-2: دومی سرمهایِ تیره است و در تمِ روشن متنِ تیره روی تیره میداد. زیرِ ۷۶۰ پیکسل ستونهای ۳ و ۴ (فی و فیِ دریافتی) پنهان میشوند تا دو ستونِ نتیجه روی موبایل کامل بمانند. - تست:
node scripts/test-goods-perf.js— ۹۱ بررسی در ۱۶ بخش. ستونِ فقراتش بازسازیِ عددبهعددِ جدولِ ویدئو است (۱٫۰۰+ / ۰٫۵۰− / ۰٫۲۰− / ۱٫۷۴۱− با جمعِ ۱٫۴۴−) و بعدش برابریِtotalGoldدر حالتِ درصدی و ریالی، خنثیشدنِ برگشتی، ثابتماندنِ پایه در برابرِ برگشتی، میانگینِ وزنی، تبدیلِ عیار، نگهبانها، مالیات، بازهٔ زمانی، دفترِ خالی و نبودِ نرخ.
#کسر و اضافه — کد ۸ (v39)
ردیفِ kind: 'discount' از v1 وجود داشت. آنچه v39 اضافه کرد جهتِ مستقل، دو میانبرِ پای سند و یک تنظیم است — و در همین مسیر دو باگِ واقعی بسته شد. توابعش با پیشوندِ disc جمعاند.
- مسئله (از ویدئوی مرجع): تهحسابِ ۸۵۴٬۰۰۰ ریالیِ یک طرفحساب باید بسته شود بیآنکه چیزی فیزیکی جابهجا شود. ویدئو صریح میگوید نه خرید/فروش (چون مظنه و فیِ طلا نباید دخیل باشد)، نه دریافتِ نقدی (صندوق نباید تکان بخورد)، نه حواله و نه چک. فقط کد ۸.
- باگِ اول — دکمه دقیقاً همانجا که لازم بود نبود. بلوکِ کسر و اضافه پشتِ
if (d.type === 'فروش' || d.type === 'خرید')قفل بود، در حالی که ویدئو همین کار را در یک سندِ دریافت انجام میدهد. گیت برداشته شد و شرط شدMath.abs(ksBal) >= 1روی ماندهٔ نقدیِ سند — یعنی دکمه هرجا که ماندهٔ بازی هست ظاهر میشود و هرجا که نیست، نه. - باگِ دوم — تخفیف در سود و زیان علامتِ وارونه داشت.
perfReportمینوشتdiscount += -rowMult(d, r) * |fi|. در سندِ فروش این یعنی تخفیفِ دادهشده سود گزارش میشد. منطقِ درست: اثرِ ردیف روی ماندهٔ طرف برابرِrowMult × (−|fi|)است، پس سهمِ مغازهrowMult × (+|fi|)میشود — و علامتِ منفی حذف شد. تستِ بخشِ ۷ همین را قفل میکند. - جهت روی خودِ ردیف مینشیند، نه روی سربرگِ سند. پرچمِ بولیِ
giveاضافه شد:give=trueیعنی «تخفیف دادم» (ضریب −۱، طرف بستانکار میشود، برای مغازه زیان) وgive=falseیعنی «تخفیف گرفتم» (ضریب +۱، سود).rowMultدر سطرِ اولش بهdiscMultواگذار میکند، پس تکْمنبعِ حقیقتِ جهت همچنان یکی است وdocDelta،docTotals،perfReportو رندرِ ردیف همگی خودبهخود درست میشوند. - سازگاری بدونِ migration.
discMultوقتیgiveنداشته باشد بهDIR[d.type]برمیگردد — یعنی رفتارِ پیش از v39، عیناً. اسنادِ قدیمی فقط در فروش و خرید ردیفِ تخفیف دارند (چون دکمهاش جای دیگری نبود) و آنجا از قبل درست بودند. هیچ دادهای دست نمیخورد و هیچ اسکریپتِ ارتقایی لازم نیست. discTail(amount, digits)=|amount| mod 10^digits. این فرمول از خودِ ویدئو استخراج شد، نه از روایتِ گوینده: با تنظیمِ ۶ کلِ ۸۵۴٬۰۰۰ رفت و مانده صفر شد؛ با ۴ فقط ۴٬۰۰۰ رفت و ۸۵۰٬۰۰۰ ماند.digitsبین ۰ و ۱۲ بریده میشود تاMath.powاز دقتِ اعدادِ صحیحِ جاوااسکریپت بیرون نزند. تنظیمشsettings.discDigitsبا پیشفرضِ ۴ است.discBalAfter(d)عمداًdocDeltaاست، نهdocTotals. پیادهسازیِ قبلیِ فرم ازbase.rial + m * docTotals(d).rialاستفاده میکرد که یک تقریب است:docTotalsجهتِ سطحِ سند را میگیرد وtashkhisِ هر ردیف (ورود/خروج/مرجوع) را نمیبیند.docDeltaهمان چیزی است که ماندهٔ واقعیِ شخص از آن ساخته میشود، پس عددِ روی دکمه با عددِ کارتِ مانده همیشه یکی است.discQuick(mode)تنها مسیرِ میانبرهاست و جهت را از علامتِ مانده میگیرد (give = bal < 0)، پس کاربر هیچوقت مجبور نیست بین دریافت و پرداخت تصمیم بگیرد.discPushهم اگر جهت به آن داده نشود همین حدس را میزند، ولی جهتِ صریح همیشه مقدم است — فرم جهت را صریح میفرستد تا انتخابِ کاربر بازنویسی نشود.- مبلغِ زیر یک ریال ردیف نمیسازد (
if (amt < 1) return false) و روی ماندهٔ صفر هم بهجای ردیفِ بیاثر، پیغامِ «چیزی برای بستن نمانده» میآید. ردیفِ تخفیفِ صفرریالی در فاکتور و گزارش خط میسازد و توضیحدادنی نیست. - طراحی: میانبرها
.ks-quickهستند — کوچک، ghost و خطچین، تا در کنارِ دکمهٔ اصلی «کارِ سریع» بهنظر برسند نه دکمهٔ هموزن؛ مبلغشان روی خودشان نوشته شده چون کلیکِ بیپیشنمایش روی چیزی که ماندهٔ حساب را عوض میکند قابلِ قبول نیست. ردیفِ ثبتشده باdr-give/dr-takeنوارِ کناریِ قرمز یا سبز میگیرد و مبلغش علامتِ−/+— همان اطلاعاتی که تا پیش از این فقط در گزارش پیدا میشد. زیرِ ۷۶۰ پیکسل میانبرها زیرِ هم میروند. - ثبتهای جانبی:
discDigits: 4درdefaults.settings؛ ورودیِs_discDigبا همزادِ غیرفعالِ «حداکثر خردهٔ بخشیدنی» در صفحهٔ تنظیمات؛ برچسبِ «کسر» درfactorRowDescبرای تخفیفِ گرفتهشده؛ بلوکِ.ks-*/.dr-*درadmin.cssبا نسخهٔ تیره؛ برچسبِ کشv=20260814a. - تست:
node scripts/test-kasr-ezafe.js— ۹۱ بررسی در ۹ بخش. ستونِ فقراتش بازسازیِ عددبهعددِ ویدئو است (۸۵۴٬۰۰۰ بدهکار → با ۶ رقم صفر، با ۴ رقم ۸۵۰٬۰۰۰) و بعدش زیانِ ۸۵۴٬۰۰۰ در سود و زیان، قاعدهٔ دریافت←زیان / پرداخت←سود، دستنخوردگیِ ردیفهای قدیمیِ بدونِgive، و بررسیهای منفی: کد ۸ پایهٔ مالیات نمیسازد، مرجوعشدنی نیست، وزن جابهجا نمیکند و «اضافه» (کد ۹) شمرده نمیشود.
#سند کارتخوان — کشیدن کارت (v40)
حسابِ پوز و تسویهاش (doPosSettle) از v29 بود؛ آنچه نبود خودِ کارتکشی از داخلِ سندِ مشتری بود. v40 همان نیمهٔ گمشده است. توابعش با پیشوندِ posSwipe جمعاند.
- مسئله (از ویدئوی مرجع): ماندهٔ ۳۱ میلیونیِ مشتری باید با کارت بسته شود، بدونِ ترکِ سند. ویدئو دو بار تأکید میکند که حسابِ اصلی را انتخاب نکنید و دلیلش را هم میگوید: «امروز هر چی توی کارتخوان کارت کشیده شده باشه، فرداش همهٔ اون کارتخوانها توی یک حواله واریز میشه به حسابتون» — یعنی سیستم ذاتاً T+1 است و انتخابِ حسابِ اصلی باعث میشود پرینتِ برنامه از پرینتِ بانک جلو بیفتد.
- چرا یک سند کافی نیست. ردیف در سندِ مشتری مینشیند ولی پول باید در حسابِ پوز بنشیند. اثرِ یک سند روی حسابِ بانکی در این موتور برابرِ جمعِ ریالیِ خودِ همان سند است (
acctDocDelta) و سربرگِ سندِ مشتری جای دیگری اشاره میکند؛ پس یک سند نمیتواند هر دو را بزند. راهِ جاافتادهٔ خودِ برنامه برای این تضاد سندِ جفتِ سمتِ بانک است (mkBankSideDoc،doPosSettle) و اینجا هم همان شد: ردیفِ سمتِ مشتری + سندِ سمتِ پوز، قفلشده به هم باposSwipeId. فریمِ ویدئو هم زیرِ همان ردیف «نمایش سند مرتبط» را نشان میدهد — یعنی خودِ کیمیا هم دو سند دارد و این تصمیم بازسازیِ رفتارِ مرجع است، نه اختراع. - سندِ جفت سرِ ذخیره ساخته میشود، نه سرِ کلیک. نسخهٔ اولِ پیادهسازی
doPosSwipeسندِ پوز را همان لحظه درstate.docsمیگذاشت وcounters.docرا جلو میبرد. این غلط بود:curDocیک نسخهٔ کاری است (JSON.parse(JSON.stringify(d))) و تاsaveDocصدا نخورَد واردstate.docsنمیشود — پس کاربری که سند را نیمهکاره رها میکرد یک سندِ یتیم و یک موجودیِ دروغینِ پوز جا میگذاشت. حالاdoPosSwipeفقط ردیف را مینشاند (باposSwipeIdوposAccIdروی خودِ ردیف) وsyncPosSwipeDocs(d)ازsaveDoc— دقیقاً بعد از نشستنِ سند و قبل ازpersist()— سندهای جفت را با ردیفها یکی میکند. syncPosSwipeDocsآشتیدهنده است، نه سازنده. از روی ردیفهای زنده بازخوانی میکند: سندِ پوزی که ردیفش رفته حذف میشود (posRole === 'pos' && posPeerId === d.id && !live[posSwipeId])، سندِ موجود در جا اصلاح میشود و سندِ نبوده ساخته میشود. نتیجهاش idempotent بودن است — ذخیرهٔ دوباره سندِ تکراری نمیسازد — و ویرایشِ مبلغ، تعویضِ دستگاه و حذفِ ردیف هر سه خودبهخود درست مینشینند. به همین دلیل هندلرِ حذفِ ردیف عمداً هیچ پاکسازیِ فوری نمیکند: حذفِ ردیف در ویرایشِ ذخیرهنشده نباید سندِ ثبتشده را نابود کند.- جهت از ماندهٔ سند میآید، نه از سربرگ.
tashkhisمطلق ست میشود ('ورود'/'خروج') تا ردیف در سندِ فروش، دریافت یا هر نوعِ دیگری یکجور رفتار کند — همان الگویی که پرچمِgiveدر کد ۸ دارد.discBalAfter(d) < 0یعنی بدهکار است و کارت میکشد؛ مثبت یعنی پول به کارتش برمیگردد. - کدِ شرحِ ۱۱ «کارتخوان» اضافه شد و عمداً زیرِ «۷ حواله» نرفت. فریمِ ویدئوی گزارش، «انتخاب ویژه» را با چهار گزینه نشان میدهد که حواله و کارتخوان در آن دو ردیفِ جداگانهاند. اگر ردیفِ کارتخوان کدِ ۷ میگرفت،
dbSpecialsOfآن راremitبرچسب میزد و گزارشِ حواله آلوده میشد. تستِ بخشِ ۷ همین را قفل میکند: ردیفِ کارتخوانposمیگیرد وremitنمیگیرد. dbSpecialsOfدو برچسبِ تازه گرفت.kasr= ردیفِkind: 'discount'یاisAddRow(کد ۸ و ۹).money=dbIsMoneyRow: سکهای کهfiدارد (چونcomputeRowMagبرای سکهٔ قیمتخورده مستقیم ریال میسازد)، یا ردیفِ ارزی در سندی که ریال هم در آن حرکت کرده. تعریفِ دوم از خودِ موتور درآمد نه از حدس:goodsRialFactorبرای ارزِ واقعی صفر برمیگرداند، پس ارز هیچوقت خودبهخود ریال نمیشود و تنها نشانهٔ پولیشدنش همنشینی با ریال در همان سند است.- گزارشِ پوز جهتِ عکس را هم میبیند.
posReceiptDocsفقطدریافترا میگیرد؛ برای «بازگشت به کارت» یک گذرِ جداگانه رویposSwipeDocs()باtype === 'پرداخت'اضافه شد و از عددِ «در انتظار تسویه» کم میشود. بدونِ این، بازگشتِ وجه در گزارش گم میشد ولی در موجودیِ پوز اثر داشت — یعنی دو عدد از هم میپاشیدند. - طراحی: کارتخوان رنگِ اختصاصیِ خودش را گرفت (
--posبنفشِ سرد) چون در همان جدول کنارِ طلاییِ کد ۸ و آبیِ مرجوعی مینشیند و باید در یک نگاه جدا باشد. انتخابِ دستگاه بهجایselectکارت است (.pw-acc) و روی هر کارت مبلغِ در انتظارِ حواله نوشته شده — چون سؤالِ واقعیِ کاربر «کدام دستگاه؟» نیست، «کدام دستگاه هنوز تسویه نشده؟» است. پیشنمایشِ زنده سه خط دارد و خطِ سومش ثابت است: «صندوق و حسابِ اصلی دست نمیخورَد» — همان جملهای که کلِ ویدئو دربارهٔ آن است. میانبرِ <kbd>Ctrl</kbd>+<kbd>K</kbd> از جملهٔ «یا کلیدهای کنترل روی کیبوردتون فشار بدید» آمد و فقط در صفحهٔ سند و روی سندِ دارای طرفحساب فعال است. زیرِ ۷۶۰ پیکسل کارتها تکستونه میشوند. - ثبتهای جانبی:
{ code: '11', name: 'کارتخوان', kinds: ['rial'] }درSHARH_CODES؛DB_QRANGESوdbApplyPresetبرای میانبرهای بازهٔ دفتر روزانه؛ دو شاخهٔ تازه درrenderDailyBook؛ بلوکِ.pw-*درadmin.cssبا نسخهٔ تیره؛ برچسبِ کشv=20260814b. - تست:
node scripts/test-pos-swipe.js— ۱۲۶ بررسی در ۹ بخش. ستونِ فقراتش بازسازیِ عددبهعددِ ویدئوست: ۳۱٬۰۰۰٬۰۰۰ روی پوز مینشیند و حسابِ اصلی صفر میمانَد؛ سه کارتکشیِ روز جمعاً ۸۰٬۰۹۷٬۰۰۰ میشوند؛ یک تسویه پوز را صفر و اصلی را همان عدد میکند. بعدش idempotent بودنِsyncPosSwipeDocs، مصونیتِ سندِ پوزِ سندِ دیگر هنگام حذف، جهتِ عکس، چهار برچسبِ «انتخاب ویژه»، و بررسیهای منفی: کارتخوان طلا و سکه جابهجا نمیکند، سودِ عیار نمیسازد، مرجوعشدنی نیست و پیش از ذخیره هیچ سندی نمیسازد.
#ماهیتِ نوع حساب — v41
«نوع حساب» از v1 فقط یک رشته بود در state.catalog.accountTypes که روی person.type مینشست و هیچجای موتور نمیخواندش. ویدئوی مرجع اما نشان میدهد که در کیمیا انتخابِ نوعِ حساب رفتارِ برنامه را عوض میکند. v41 همان لایهٔ گمشده است: یک ماهیت پشتِ هر عنوان.
- مدلِ داده.
ACC_NATURESهشت رکوردِ{key, title, ic, color, desc}است و نگاشتِ کاربر درstate.catalog.accountNaturesمینشیند ({ 'عنوان': 'key' }). عنوانِ بدونِ نگاشت یعنیwholesaleیعنی بیرفتار. هیچ migrationای لازم نیست و دفترِ موجود عیناً همان اعداد را میدهد؛ تست بخشِ ۱۴ همین را قفل میکند. accNature(type)سهمرحلهای است و مرحلهٔ چهارم عمداً وجود ندارد. اول نگاشتِ صریح، بعد تطابقِ دقیقِ عنوان باACC_NATURES[].title، وگرنهwholesale. حدسِ فازی و تطابقِ جزئی نداریم: اگر «سرمایهگذار» (که یکی از شش نوعِ پیشفرضِ محصول است) خودبهخودcapitalمیشد، اسنادِ همهٔ سرمایهگذارها یکشبه از سود و زیان بیرون میافتادند و کاربر میدید سودِ پارسالش عوض شده. رفتار باید انتخابِ آگاهانه باشد نه اثرِ جانبیِ نامگذاری.- نقاطِ اتصال کم و مشخصاند.
docIsCapitalAcct(d)درperfBucketOfوgpRowOkسندهای مالک را از هر دو موتورِ سود بیرون میگذارد.docIsRetailAcct(d)ورودیِdocApplyNatureوdocApplyRetailFiوdocAddRowاست. بقیه فقط نمایشاند (تختهٔ ماهیت، تراشهها، پنهانسازیِamanatاز فهرستِ روزمره). هرچه سطحِ تماس کمتر، احتمالِ رگرسیون کمتر. docApplyNatureیک بار و فقط روی سندِ بکر عمل میکند. باd.natureAppliedقفل میشود و اگرrowHasDataروی هر ردیفیtrueباشد اصلاً وارد نمیشود. دلیلش ساده است: کاربری که واحدِ قیمت را دستی روی مظنه گذاشته و نصفِ سند را زده، نباید با عوض کردنِ طرفحساب کارش را از دست بدهد. همین منطق درdocApplyRetailFiهم هست — ردیفی کهfiدارد بازنویسی نمیشود و تابع فقط تعدادِ ردیفهایی که واقعاً پر کرده را برمیگرداند.accSeedStandardجمعکننده است، نه جایگزین. عنوانِ نبوده را اضافه میکند و ماهیتِ هر هشت عنوانِ مرجع را مینشاند؛ عنوانهای کاربر را نه حذف میکند نه تغییر میدهد.accNatureSet(t, '')هم نگاشت را پاک میکند نه اینکهwholesaleبنویسد — پس حذفِ یک عنوان زباله جا نمیگذارد.- طراحی: هر ماهیت دو متغیرِ CSS دارد (
--natو--nat-s) که روی کلاسِ.n-<key>مینشینند، و همهٔ اجزا — کارتِ تخته، انتخابگرِ جدول، تراشهٔ کنارِ نام، راهنمای فرمِ شخص، یادداشتِ بالای سند — از همان دو متغیر رنگ میگیرند. یعنی افزودنِ ماهیتِ نهم یک ردیفِACC_NATURESاست و یک ردیفِ CSS، نه گشتن در ده جا. رنگِ نرم دستی نوشته شده (rgba) نه باcolor-mix، تا شفافیتِ حالتِ تیره جدا تنظیم شود.natHintHtmlزیرِ انتخابگرِ فرمِ شخص باonchangeزنده بهروز میشود — چون سؤالِ «این نوع چه میکند؟» باید پیش از ذخیره جواب بگیرد، نه بعدش.
#ریز سود و زیان — v41
ویدئوی مرجع یک جملهٔ کلیدی دارد: «وقتی شما دو بار کلیک بکنید روی این ردیف، یک سربرگ جدید برایتان باز میشود». دو تصمیمِ طراحی مستقیماً از همین جمله آمدهاند: دابلکلیک (نه تککلیک، تا کلیکِ اتفاقی کاربر را از گزارش بیرون نبرد) و سربرگِ تازه (نه جایگزینیِ نما، تا گزارشِ اصلی سرِ جایش بماند).
- مسئلهٔ اصلی، دو بار حساب کردن بود. سادهترین راه این بود که برای جدولِ ریز یک حلقهٔ تازه روی
state.docsنوشته شود. این حتماً روزی از خلاصه جدا میافتاد: هر اصلاحِ آینده درperfReportباید در دو جا تکرار میشد. بهجایش حلقهٔ ردیفهایperfReportبه بیرون کشیده شد و شدperfRows(period, market)— یک رکورد بهازای هر ردیفِ مؤثر با{docId, docType, code, date, person, name, bk, dir, mult, coin, w, qty, fi, amount, wage, priced, gold, rial}. حالاperfReportمصرفکنندهٔperfRowsاست و خودش فقط جمع میبندد. برابریِ ریز و خلاصه دیگر یک ادعا نیست، ساختاری است. تست هم همین را میسنجد:جمعِ ریزها = جمعِ خلاصه. bkکلیدِ درِل است. برای ردیفهای معامله همان کلیدِperfBucketOf، برایkind: 'discount'مقدارِ'kasr'و برایisAddRowمقدارِ'ezafe'. سطرهایothersدر خروجیِperfReportهم همینbkرا با خود میبرند تا سطرِ خلاصه بداند به کدام درِل وصل است. سطرهای بدونِbk(سودِ عیار، مالیات) عمداً درِل ندارند چون ردیفِ متناظرِ قابلِ نمایش ندارند.pnlRows(spec)تنها تابعِ جدولِ ریز است و هر دو موتور را میپوشاند:spec.kind === 'goods'ازgpRowsفیلتر میکند (مبنای فیِ دریافتی)، وگرنه ازperfRows(مبنای نرخ روز).dirخالی یعنی هر دو جهت — همان چیزی که سطرِ جمعِ گروه لازم دارد. مرتبسازی بر تاریخ است تا ستونِ ترازِ تجمعی معنا داشته باشد.pnlعمداً درALL_VIEWSنیست. مقصدِ منو نیست و ثبتش درALL_VIEWSیک تیکِ دسترسیِ بیمعنا در اتاق فرمان میساخت. همان الگویی کهsetupدارد: درTITLESهست، درALL_VIEWSنیست، وcanView('pnl')بهcanView('reports')گره خورده — چون هرکس گزارش را میبیند حقِ دیدنِ ریزش را هم دارد و برعکس.- درِل مالِ سربرگ است، نه مالِ برنامه.
pnlDrillدرstashActiveرویt.drillمینشیند و درadoptTabبرمیگردد — دقیقاً همان کاری کهcurDoc/t.docبرای سربرگِ سند میکند. بدونِ این، باز کردنِ درِل دوم، درِل اول را در سربرگِ قبلی خراب میکرد.tabTitleهم برایpnlازpnlTitle(t.drill)عنوان میسازد تا کاربر با پنج سربرگِ باز بداند کدام کدام است. - سیمکشیِ رابط با
data-*است نه با هندلرِ دستی. سطرهای خلاصه فقطdata-dk/data-bk/data-dir/data-lblمیگیرند وpnlBindDrill(root, period, periodLabel)یک بار روی کلِ صفحهٔ گزارشها میدود و همه را بایند میکند. افزودنِ درِل به یک جدولِ تازه یعنی چهارdata-روی<tr>، بدون دست زدن به منطق. - طراحی:
.dk-ableنشانگر را بهzoom-inمیبرد و زبانهٔ کارکرد اجناس نشانِ⤢میگیرد — چون قابلیتِ نامرئی وجود ندارد. ستونِ آخرِ جدولِ ریز ترازِ تجمعی است نه فقط سود، چون سؤالِ واقعیِ کاربر «این ردیف چقدر بود؟» نیست، «سود از کجا جهید؟» است. دابلکلیکِ دومِ روی ردیفِ ریز سندِ اصلی را باز میکند (stkOpenDoc)، پس مسیرِ کاملِ «عدد ← ردیف ← سند» دو دابلکلیک است. - ثبتهای جانبی:
gpRowsدو فیلدِcodeوpersonگرفت تا جدولِ ریز نامِ طرفحساب داشته باشد؛<section id="view-pnl">درadmin.html؛ بلوکِ.pnl-*/.dk-ableدرadmin.cssبا نسخهٔ موبایل؛ برچسبِ کشv=20260814c. - تست:
node scripts/test-acc-nature.js— ۱۵۸ بررسی در ۱۵ بخش. مهمترینهایش رفتاریاند نه ساختاری: سندِcapitalسودِ ۱٬۰۰۰٬۰۰۰ ریالی نمیسازد و بهمحضِ برداشتنِ ماهیت دوباره شمرده میشود (یعنی رفتار واقعاً به ماهیت بند است نه به چیزِ دیگری)؛ جمعِpnlRowsبا سطرِ خلاصه در هر سه حالتِ جهتدار، بیجهت و کارکردِ اجناس یکی است؛ سندِ تکفروشیpriceUnit: 'gram'وtaxOn: trueمیگیرد ولی سندِ دارای ردیفِ پرشده دست نمیخورَد؛ و هر شش نوعِ پیشفرضِPERSON_TYPESبهwholesaleمیرسند.
#کار جور — v43
ویدئوی مرجع نُه دقیقه است و کاری را دستی میکند که هر سه بخشش قابلِ اتوماسیون بود: صفر کردنِ سه قلم، تعریفِ قلمِ تازه، و ضربوتقسیمِ ماشینحسابِ ویندوز برای اجرت و فیِ میانگین. v43 هر سه را در یک فرم جمع میکند. توابعش با پیشوندِ joor جمعاند و هستهٔ ریاضیاش یک تابع است: joorMix(parts).
- قاعدهٔ نگهبان، در یک جمله: ادغام هیچ طلایی نمیسازد و نمیسوزاند. سمتِ انبار معادلِ ۷۵۰ را موبهمو نگه میدارد، و سمتِ فاکتور تا وقتی کاربر نرخِ تازهای نگذارد ریالِ سند را تکان نمیدهد. هر انحراف باید قصدِ کاربر باشد و پیش از ثبت دیده شود.
joorMixدرصد را برعکس حساب میکند. ویدئو «وزنِ بابتِ درصد ÷ کلِ وزن» میزند. اینجا اولvaznوkaratگرد میشوند (میانگینِ وزنی برای عیار، نه ساده)، بعدpctاز روی همان عددهای گردشده حل میشود تاadjEq(vazn, karat, pct) == Σ adjEq(vᵢ, kᵢ, pᵢ). برای عیارِ یکسان دقیقاً به فرمولِ ویدئو تقلیل پیدا میکند؛ برای عیارِ نایکسان فرمولِ ویدئو غلط است. ترتیبِ گرد کردن عمدی است: اگرpctاول ساخته شود، گردکردنِ وزن مانده را از صفر میکَنَد.joorPctشش رقم است، نه سه — و این یک باگِ واقعی بود. نسخهٔ اولdest.pctرا باjoorR3مینوشت. روی همان ۵۲۳٫۷۹ گرمِ ویدئو، ۳٫۸۹۰۴۹۰٪ که به ۳٫۸۹ گرد میشد ۰٫۰۰۳ گرمِ معادل را میخورد وadjPlan().eqNetدیگر صفر درنمیآمد — یعنی این ماژول سرِ نمونهٔ خودِ ویدئو رد میشد. با شش رقم، خطای گردکردن روی هر کیلو طلا زیرِ ۵ میلیونیمِ گرم میماند (صد برابر ریزتر ازADJ_EPS) و عدد هم هنوز خواندنی است. تست همین را از دو طرف قفل میکند: با شش رقم مانده صفر است، با گردکردنِ درشتتر نیست.- سمتِ انبار روی موتورِ v14 سوار است، نه کنارش.
joorInvItems(plan)خروجیاش مستقیم خوراکِadjPlan/adjApplyاست. نتیجه: سند از همان روزِ اول «لغو» دارد، در «اصلاحهای اخیرِ موجودی» دیده میشود و هیچ مسیرِ ثبتِ موازیای ساخته نشد. ترتیبِ داخلِ تابع مهم است —dest.pctوdest.karatپیش از برنامهریزی نوشته میشوند، چونadjPlanمعادل را از روی همین دو عدد میخواند. - ماندهٔ سند نمایشداده میشود، حساب نمیشود. فرمِ انبار عددِ مانده را با یک
adjPlanروی یک ردیفِ_probeاز خودِ موتور میگیرد، نه از حسابِ خودش. اگر روزیadjPlanعوض شود، این عدد هم با آن عوض میشود و دروغ نمیگوید. ویدئو در همان صحنه یک صفرِ اضافه تایپ میکند و مانده چند میلیارد میپرد و فقط چون کاربر نگاهش میکند لو میرود؛ اینجا عددی برای تایپ کردن نمانده. joorDestStateسختگیر است و باید باشد. مقصد باید تازه یا صفر باشد. ادغام روی قلمی که موجودی دارد،pct/fiِ آن را عوض میکند و موجودیِ قدیمیاش را بیسند تجدید ارزش میکند — سود یا زیانی که هیچ ردیفِ سندی پشتش نیست، یعنی دقیقاً همان چیزی که کلِ v14 قرار است نگذارد اتفاق بیفتد. ویدئو هم همین را رعایت میکند («اسمش را قبلاً تعریف کردهایم، فقط موجودی ندارد»).- سمتِ فاکتور عمداً قاعدهٔ دیگری دارد. اولین طراحی میخواست ریالِ ردیفِ ادغامشده را هم عیناً حفظ کند. ترنسکریپت این را رد کرد: «و همه رو با فی پرداختی شیش درصد بدیم به مشتری» — مغازهدار لاتِ ادغامشده را با نرخِ چانهزده میفروشد (۶٪) نه با میانگینِ بهای تمامشده (۳٫۸۹٪). پس ثباتِ مانده مالِ سندِ داخلیِ انبار است و نرخِ فاکتور یک تصمیمِ تجاری است که اثرش باید نشان داده شود، نه تحمیل. به همین دلیل دو نقطهٔ ورودیِ جدا شد، نه یکی.
jdPct()گردکردنِ نمایش را از ثبت جدا میکند. کادرِ نرخ، نرخِ خنثی را تا سه رقم نشان میدهد چون ۳٫۸۹۰۴۹۰۴۶٪ عددی نیست که کسی تایپ کند. ولی اگر کاربر دستش را به کادر نزده باشد، ثبتِ همان ۳٫۸۹ حدودِ ۳٬۸۵۳ ریال از جیبش برمیداشت و پایینِ فرم «زیان» مینوشت — بابتِ کاری که نکرده. پس تا وقتی عدد همان گردشدهٔ نرخِ خنثی است، نرخِ خنثیِ دقیق ثبت میشود.- آستانهٔ ۲۰٪ برای هشدارِ صفرِ اضافه. پایینتر از این، نوسان به چانهزنیِ واقعی میخورَد (۳٫۸۹٪ → ۶٪ فقط ۲٪ اثر دارد و نباید هشدار بدهد)؛ بالاتر از این، احتمالِ اشتباهِ تایپی از احتمالِ تصمیم بیشتر است (۳٫۸۹٪ → ۶۰٪ یعنی ۵۴٪ اثر). تست هر دو طرفِ آستانه را میسنجد.
joor.partsکپیِ عمیق است، نه ارجاع. «باز کردنِ ادغام» چیزی را بازسازی نمیکند؛ همان ردیفها را که ذخیره شدهاند برمیگرداند. به همین دلیلjoorRowsCheckادغامِ تودرتو را رد میکند — ردیفِ ادغامشده باید اول باز شود تاpartsدو لایه نشود.joorBuildRowوقتیfiصفر است حالت عوض میکند. درصدی از هیچ معنا ندارد، پس اجرتmode: 'fi'(گرمی) میشود تا ریالِ اجرت همان بماند که بود. بدونِ این شاخه، ادغامِ ردیفهای بیفی کلِ اجرت را صفر میکرد.- ثبتهای جانبی: دکمهٔ
joorInvدرadjBarHtml(فقط با ≥۲ انتخاب)، دکمهٔdSelJoorدرrenderDocSelBar، دکمهٔdata-joorsplitدر سلولِrow-acts؛ بلوکِ.joor-*و.ds-actدرadmin.css؛ برچسبِ کشv=20260815a. - تست:
node scripts/test-joor.js— ۱۴۷ بررسی در ۱۰ بخش. همهٔ عددها از دو سندِ واقعیِ ویدئو (کد ۳۶۴ و ۳۶۵) درآمدهاند. مهمترینها: ماندهٔ سندِ ادغام صفر است و لغو هر سه قلم را دقیقاً برمیگرداند؛ فرمولِ ما و فرمولِ ویدئو روی عیارِ نایکسان از هم جدا میشوند و اختلافش به گرم سنجیده میشود؛ نرخِ خنثیِ سمتِ فاکتور از راهی کاملاً دیگر به همان ۳٫۸۹۰۴۹۰۴۶٪ میرسد؛ و «باز کردنِ ادغام» جمعِ ریالی را موبهمو به عددِ پیش از ادغام برمیگرداند.
#آبشدهٔ شرطی — v44
ویدئوی مرجع هفت دقیقه است و کاری را نشان میدهد که در اصلْ درست است: طلایی که عیارش معلوم نیست با یک عیارِ موقت ثبت میشود و بعداً تصحیح. سه جا اما میلنگد و v44 هر سه را میبندد. توابعش با پیشوندِ cond جمعاند.
- قاعدهٔ نگهبان، در یک جمله: جوابِ ریگیری «تجدیدِ ارزیابی» است، نه معامله.
vaznدست نمیخورد،fiدست نمیخورد،computeRow().rialدست نمیخورد؛ فقطayar— و در نتیجهrowW750Phys— عوض میشود. تست هر سه را بهازای هر سه سندِ نمونه قفل میکند.
- مدلِ داده عمداً کمینه است. عیارِ موقت روی خودِ
r.ayarمینشیند و چهار فیلدِ کمکی کنارش:condOpen(منتظرِ جواب)،condBase(مبنای مهرشده)،condAns/condAnsAt(جواب و تاریخش)، بهعلاوهٔrefiner/receiptبرای هویتِ لُنگه. نتیجه:rowKaratPhys،rowW750،computeRowوdocDeltaهیچ تغییری نکردند. کلِ قابلیت روی موتورِ موجود سوار است، نه کنارش.
- فیکس ۱ —
condBaseقفلِ تنظیمات را بیموضوع میکند. ویدئو «عیار مبنای شرطی» را یک تنظیمِ جهانیِ زنده میگیرد و برای همین مجبور شده قفلش کند: «تا یه آبشدهٔ شرطی موجود باشه، اجازه نمیده عیار مبنا رو تغییر بدین.» علتِ قفل درست است — اگر مبنا زنده خوانده شود، عوضکردنش ماندهٔ همهٔ لُنگههای بازِ قبلی را عقبگرد بازنویسی میکند. ولی نتیجهاش این است که در بنکداریِ واقعی (شمارندهٔ خودِ ویدئو ۱۶ لُنگهٔ باز نشان میدهد) آن تنظیم هرگز قابلِ تغییر نیست. اینجاcondStamp(r)مبنا را هنگامِ ثبت روی ردیف مهر میکند و تنها جایی است کهstate.settings.condKaratخوانده میشود؛ از آن به بعد ردیف عددِ خودش را دارد. پس تنظیم فقط پیشفرضِ لُنگههای تازه است و قفل لازم نیست.condStampعمداً idempotent است — مهرِ زدهشده دوباره پر نمیشود، وگرنه هر بار رندر شدنِ سند عیار را جابهجا میکرد.
- فیکس ۲ — عیارِ موقت روی
ayarاست، نهayarCalc. ویدئو میگوید عددِ حدسی را در ستونِ «عیار شخصی» بنویس. در این کدبیسayarCalcمعنای دیگری دارد: اختلافش با عیارِ فیزیکی مستقیم بهrowKaratGainو از آنجا به سودِ عیار میرود. حدسِ ۷۳۵ روی ۳۸۴٫۳۲ گرمِ خودِ ویدئو ۷٫۶۸۶ گرم «زیانِ عیار» جعل میکرد — زیانی که رخ نداده، چون عیار فقط نامعلوم است نه باخته. با نشستنِ عیارِ موقت روی عیارِ فیزیکی،rowKaratGainتا رسیدنِ جواب دقیقاً صفر است و ستونِ «عیار شخصی» برای کارِ اصلیاش آزاد میماند.
- هویتِ لُنگه =
condLotKey(refiner, receipt). نرمالسازی: فاصلههای تکراری جمع،trim، وtoLowerCase؛ دو بخش با\u0000جدا میشوند تا «فارس/۱۲» و «فار/س۱۲» یکی نشوند. ردیفهای بیشناسنامه همه یک کلیدِ خالی میگیرند و عمداً در یک سطرِ «بیشناسنامه» جمع میشوند تا به چشم بیایند، نه اینکه هر کدام یک سطرِ یتیم بسازند.
- فیکس ۳ —
condAnswerPlanپیش ازcondAnswerApply. ثبتِ جواب در ویدئو یک جملهٔ قرمز است و یک «مطمئنی؟»؛ همان یک کلید ماندهٔ چند طرف حساب را جابهجا میکند و نه پیشنمایشی دارد نه برگشتی.condAnswerPlanاثر را به تفکیکِ طرف حساب برمیگرداند، چون کاربر ماندهٔ اشخاص را میفهمد نه «مجموعِ دلتای وزنِ ۷۵۰». فرمولِ هر ردیف:mult × vazn × (to − karat) / karatBase. تست خالصِ این جمع را از راهِ دیگری هم میسنجد — باید دقیقاًماندهٔ لُنگه × (جواب − مبنا) ÷ مبناباشد.
condKaratCheckمرزها را همانجا میگیرد. بالای ۱۰۰۰ رد (طلای خالص سقف است، و ۷۴۷۰ بهجای ۷۴۷ همانجا لو میرود)، صفر و منفی رد، زیرِ ۶۵۰ قبول ولی با هشدار. عمداً هشدار است نه رد: آبشدهٔ پایینعیار وجود دارد، فقط نادر است.
- لغو از snapshot برمیگرداند، نه از تنظیمات.
condAnswerApplyپیش از تغییر،{ayar, condOpen, condAns, condAnsAt}هر ردیف را روی خودِ توکنِstate.condLogمینویسد. اگر لغو ازcondDefaultKarat()میخواند، تغییرِ تنظیمات بینِ ثبت و لغو ردیف را به عیارِ اشتباه برمیگرداند — تست دقیقاً همین سناریو را دارد. دفترچه روی ۲۰۰ رویداد سقف دارد.
- ردیفهای پیش از v44 پرچم ندارند و «باز» فرض میشوند (
condIsOpenروی!== falseمیسنجد، نه=== true). کدِ شرحِ ۳ بهخودیِخود یعنی عیارش شرطی است؛ بدونِ این شاخه، هر لُنگهٔ قدیمی بیسروصدا از دفتر میافتاد.condClearهم قرینهاش است: ردیفی که دیگر شرحِ ۳ نیست پرچمهایش را پس میدهد، ولیayarش دستنخورده میماند چون آن عدد داده است نه پرچم.
- دفتر «لُنگهمحور» است، نه «ردیفمحور». گزارشِ ویدئو فهرستی از ردیفهاست. اینجا
condGroup()واحدِ کار را لُنگه میگیرد و ردیفها زیرِ سطر باز میشوند — چون یک جواب به یک لُنگه میخورد، نه به یک ردیف.net = inW − outWهم همان جمعی است که ویدئو دستی روی سه سند میزند؛ منفیشدنش یعنی بیش از دریافت پخش شده و قرمز میشود.
- ثبتهای جانبی: ردیفِ زیرینِ
condRowHtml(دوقلویchkRowHtml)، نشانِcondFlagروی ستونِ عیار باreadonlyشدنِ خودِ ستون، مهرِcondStamp(condClear(r))روی تغییرِkindوsharhدرrenderDocRows، تبِ «دفتر شرطی» داخلِRENDER.melt، کادرِs_condKaratدر تنظیمات؛ بلوکِ.cond-*درadmin.css؛ برچسبِ کشv=20260816a.
- تست:
node scripts/test-sharti.js— ۱۴۹ بررسی در ۱۱ بخش. عددها از خودِ ویدئو (لُنگهٔ فارس آنالیز ۴۶۵۲۴۶۱ با ۶۰۴٫۸۱/۲۵۴٫۴۹/۱۲۸٫۴۹ و ماندهٔ ۲۲۱٫۸۳؛ ردیفهای ۲۶۱٫۵۱@۷۴۸ و ۳۸۴٫۳۲@۷۳۵؛ جوابهای ۷۴۷/۷۴۶/۷۴۵). مهمترینها: تغییرِ تنظیمات ردیفِ مهرخورده را تکان نمیدهد؛ راهِ ویدئو ۷٫۶۸۶ گرم زیانِ ساختگی میسازد و راهِ ما صفر؛ اثرِ ثبتِ جواب برdocDeltaهر سند دقیقاً همان عددی است که در پیشنمایش نشان داده شده؛ و لغو، عیارِ مهرشده را برمیگرداند حتی اگر تنظیمات بینِ ثبت و لغو عوض شده باشد.
#مرجوعیِ بنکداری — دفترِ فی و خرید خالص — v45
ویدئوی مرجع ده دقیقه است و هفت قاعده دارد. چهارتایش از قبل پیاده بود و ممیزیِ کد پیش از هر تغییری همین را نشان داد: gpBasis ردیفِ tashkhis === 'مرجوع' را از پای خودت بیرون میگذارد (v38)، علامتِ زیانِ ٪۶ در برابر ٪۱۲ از خودِ rowMult میآید و شاخهٔ جداگانه ندارد، retAsk همان پنجرهٔ «همین سند / سند جدید» با Ctrl+R است (v20)، و retPeerGoods فهرستِ پیشنهادی را به اجناسِ همان شخص محدود میکند. سهتای باقیمانده اضافه شد.
feeBookFor(personId, type, name, skipId, needFi)جایlastFeeForرا گرفت وlastFeeForنازکپوششِ رویش شد. دفترِ فی از v39 وجود داشت ولی فقطr.fiرا میخواند. برای بنکداری این یعنی دفترِ خالی: کارِ ساخته فیِ ریالی ندارد، «فیِ کار» همان درصدِ اجرت است.feeBookForهر دو را برمیگرداند ({ts, fi, pct, code}) وlastFeeForباneedFi = trueقراردادِ قبلیِ «انتقال سند» را دستنخورده نگه میدارد — آنجا عمداً فقط فی منتقل میشود، پس ردیفِ بیفی نباید کاندید باشد.
feeRowishدروازهٔ اصلی است و همان یک شرط قاعدهٔ سختِ این بخش را میسازد:!isRetRow(r). بدونش مرجوعیِ ٪۶ آخرین رکوردِ انگشتر مروارید میشد وfeeBookApplyدفعهٔ بعد ٪۶ پیشنهاد میداد. این شرط از قبل درfeeRowishبود (برای انتقال سند)، و حالا دفترِ درصد هم از همان دروازه رد میشود — یعنی یک نگهبان، نه دو تا.
feeBookApply(r)روی هر دو شاخهٔdocResolveGoodsسوار است (کالای شناختهشده و کالایی که همان لحظه تعریف میشود)، بعد ازapplyGoodsTypeتا کاتالوگ اولویت داشته باشد. چیزی که پُر است دست نمیخورد — نه فیِ دستیِ کاربر و نه اجرتی که از کاتالوگ آمده. و مثلapplyGoodsSaleWageیکtoastمیگوید عدد از کجا آمد؛ قاعدهٔ این پرونده این است که حدسِ خاموش بدتر از خالیِ آشکار است، پس پیشنهاد باید دیده شود.
docDirWarn(d)ازdocPermWarnجدا است، عمداً. در ویدئو تنها دلیلِ دیدنِ «از مشتری کار دریافت نمیکنی» غیرمجاز بودنِ آن عملیات برای آن گروه است؛ یعنی بدونِ گروهبندی هیچ هشداری نیست. اینجا معیارp.typeاست و بهgroupIdکاری ندارد. سه محدودیت هم عمدی است تا هشدار پرحرف نشود: فقط سندِ دریافت/پرداخت، فقطrowPermKind(r) === 'sakhte'، و ردیفِ مرجوعی معاف. درsaveDocبندِ<p class="wb-perm">خودش را دارد و باwarnدر یک رشته قاطی نمیشود — دو خبرِ متفاوتاند و باید جدا خوانده شوند.
GP_NETS+P.netsپاسخِ «خرید خالص». چهار جفت از رویGP_PAIRخالص میگیرند و فقط وقتی ساخته میشوند که گروهِ مرجوعی در آن دوره وجود داشته باشد (if (!b) return null)؛ وگرنه خالص همان اصل است و یک جدولِ بیحرف اضافه میشد. عددها ازg.wمیآیند نه از یک جمعِ تازه، پس جدولِ خالص و جدولهای بالا نمیتوانند از هم واگرا شوند.
- چرا خطای «تشخیصِ عادی» دوبرابر است. برچسب از
gpLabel(d, r)میآید، و آن فقطd.typeوr.tashkhisرا میخواند. مرجوعیِ ثبتشده با تشخیصِ عادی برچسبِ گروهِ اصلِ جهتِ مخالف را میگیرد: در صحنهٔ ۲ میرود زیرِ «پرداخت». پس هم از «دریافت خالص» کم نمیشود و هم زیرِ سرفصلِ بیربط جمع میخورد. تست همین را با یک تفریق مهر میکند:دریافت.w − ۶۵٫۷۸ = ۳۴٫۲۲.
- کلیدِ دفتر شاملِ نوعِ سند است و همین یک گودالِ ویدئو را پر میکند. ویدئو میگوید ٪۶ِ ثبتشده در سندِ پرداخت در دفترِ فیِ جنس مینشیند و برای اصلاحش باید یک سندِ دریافتِ ٪۱۲ الکی زد.
feeBookForرویx.type !== typeرد میکند، پس آن مسیر از اول بسته است. ولی این جانشینِ قاعدهٔ مرجوعی نیست: ردیفِ عادیِ ٪۶ داخلِ سندِ دریافت همچنان دفتر را خراب میکند — تست این حالت را هم صریح ثبت کرده تا کسی روزی یکی از دو نگهبان را بهخیالِ اضافیبودن برندارد.
- ثبتهای جانبی:
GP_NETSکنارِGP_ORDER/GP_PAIR؛ جدولِ خالص درgpSectionHtmlپیش از جدولِ مالیات، با کلاسهای موجودِ.gp-tbl/.gp-note/.hint(CSS تازهای لازم نشد)؛ برچسبِ کشv=20260817a. سه تستِ همسایه بهروز شدند چون وابستگیشان عوض شد:GP_NETSبه فهرستِ استخراجِtest-goods-perfوtest-acc-natureاضافه شد، وtest-doc-move— که با استاب کار میکند — استابِgpPctگرفت، چون دفترِ فی از این نسخه درصدِ اجرت را هم میخواند.
- تست:
node scripts/test-fee-book.js— ۱۱۵ بررسی در ۸ بخش. عددها از خودِ ویدئو (دستبند رولکسِ ۲۴٫۸۰۰ با پایِ ٪۱۰ و اجرتِ ٪۱۵؛ انگشتر مرواریدِ ۳۴٫۲۲۰ با پایِ ٪۱۲ و مرجوعیِ ٪۶). مهمترینها: زیانِ مرجوعی دقیقاً۲٫۰۵۳۲گرمِ ۷۵۰ درمیآید؛ خرید خالص۱۰۰ − ۳۴٫۲۲ = ۶۵٫۷۸؛ راهِ درست پایه را روی ٪۱۲ نگه میدارد و راهِ غلط همان جنس را به ٪۱۰٫۹۹ میبرد؛ مرجوعیِ صحنهٔ ۱ سودِ پرداخت را موبهمو خنثی میکند و سودِ دوره صفر میشود؛ و گزارشِ بیمرجوعی جدولِ خالص نمیسازد. ویدئو میانگینِ بههمریخته را ۱۰٫۹۱ نشان میدهد؛ وزنِ دریافتِ اولیهاش روی صفحه نیست، پس تست با وزنِ ۱۰۰ همان فرمول را میسنجد نه همان رقم را.
#فیِ فروش نقدی، فیِ نسیه و تخفیفِ خوشحساب — v46
ویدئوی مرجع نُه دقیقه است و هفت قاعده دارد. دوتایش از قبل پیاده بود و ممیزیِ کد پیش از هر تغییری همین را نشان داد: applyGoodsType فیِ ریالیِ کاتالوگ (cashFi) را از v7 روی همهٔ انواعِ سند میریخت، و gpBasis از v38 دقیقاً همان «فیِ دریافتی» را میساخت — فقط هیچکس بیرون از گزارش صدایش نمیزد. پنجتای باقیمانده اضافه شد.
applyGoodsSaleWageازcurDoc.type !== 'فروش'درآمد و بهfeeSaleSide(d)رسید (فروشیاپرداخت). این تکخطی گودالِ اصلیِ ویدئو را پر میکند: صحنهٔ ٪۶/٪۸ کلاً بنکداری است و سندش «پرداخت»، پسsalePctدقیقاً جایی که به کار میآمد اعمال نمیشد.دریافت/خریدعمداً بیرون ماندند — فیِ فروش نرخِ دادن است و اگر آنجا مینشست، پایِ خودت را با نرخِ فروش آلوده میکرد. همراهش یکif (r.wage) returnهم اضافه شد: تا v45 لازم نبود چون ردیفِ سندِ فروش تازهساز بود، ولی در بنکداری کاربر معمولاً درصد را قبل از نامِ جنس میزند.
docFeeChain(r, g)سه صدازدن را در یک تابع جمع کرد، چون ترتیبشان خودش قاعده است و نباید بین دو نقطهٔ صداکنندهٔdocResolveGoodsواگرا شود:applyGoodsType→feeBookApply→feeRecvApply. ترتیبِ v45 دستنخورده مانده (کاتالوگ مقدم بر دفتر) و فقط یک حلقه تهش اضافه شده.
feeRecvFor(name, ayar)رویgpBasis()سوار است، نه روی یک پیمایشِ تازه. همین یک تصمیم است که نمیگذارد پیشنهادِ فی و گزارشِ سود دو حرفِ متفاوت بزنند: هر دو از یک تابع میخوانند. واگراییِ عمدی با کیمیا هم همینجاست — آنجا «آخرین عدد» است، اینجا میانگینِ وزنی.gpBasisهر بار کلِstate.docsرا میپیماید و این تنها جایی است که بیرون از گزارش صدا زده میشود؛ چون محرکش تایپِ نامِ جنس است (نه رندر)، حافظهٔ میانی لازم نشد.
nasieApply(r, srcFi, srcW)و قاعدهٔ سختش:list = s === 'cat' || s === 'recv'. مازادِ نسیه هرگز روی عددِ دفترِ فی نمینشیند، چون آن عدد ثبتِ قبلیِ همین شخص است و مازادش را از قبل دارد؛ سوارکردنِ دوباره یعنی رشدِ پلهای (۸ → ۱۰ → ۱۲ → ۱۴).srcFi/srcWعمداً روی خودِ ردیف ذخیره نمیشوند: پرچمِ ماندگار یعنی یک فیلدِ تازه در هر سند، و این عدد بعد از ثبت هیچ مصرفی ندارد.feeNasieDocهم فقطپرداخترا میپذیرد — همان «در تکفروشی فیِ نسیه نداریم».
feeOffFlag(d, r)هشدار است نه سد، و عمداً درsaveDocنیست. بندِ «بازبینی سند» برای چیزی است که باید قبل از ثبت تصمیم بگیری؛ این یکی باید کنارِ خودِ عدد دیده شود، همانجا که تایپ شده. با کلاسهای موجودِ.row-prof.rp-warnرندر میشود و CSS تازهای لازم نشد. معیارشfeeExpectPctاست که مازادِ نسیه را داخلِ خودش حساب میکند، وگرنه هر سندِ نسیهای یک هشدارِ کاذب میگرفت. چهار سکوتِ عمدی: مرجوعی، اجرتِ غیردرصدی، سندِ دریافت/خرید، و جنسِ بیsalePct.
- تخفیفِ وزنی با کد ۹ (
sharh: '9') ثبت میشود، نه با یکkindتازه. سه خاصیتِ کد ۹ دقیقاً همان چیزی است که تخفیف لازم دارد: روی مانده مینشیند،stkRowSubjبیرونش میگذارد (پس نه در کاردکس دیده میشود و نهgpBasisرا رقیق میکند)، و در سود و زیان زیانِ طلایی است. پیشینهاشleaseAccrualRowاز v42 است.ghDiscBaseبر حسبِrowW750بسته میشود نه وزنِ خام (سندِ مختلطعیار وگرنه عددِ بیمعنا میداد) و دو استثنا دارد:isRetRowوisAddRow— دومی یعنی تخفیفِ دوم روی تخفیفِ اول سوار نمیشود.ghDiscDirجهت را ازghBalAfterمیگیرد و از کاربر نمیپرسد، همان قاعدهٔ کد ۸.
- ثبتهای جانبی:
nasieFi/nasiePctدرpersonForm(هر دوnum، پس ردیفهای قدیمی صفر میگیرند و رفتار عوض نمیشود)؛gtRecvHint(ex)کادرِ خواندنیِ فیِ دریافتی درgoodsTypeForm؛ دکمهٔdGhDiscدر پابرگِ سند با شرطِghDiscBase(d) > 0.0005(سندِ صرفاً ریالی پایهای برای درصد ندارد)؛ برچسبِ کشv=20260817b. سه تستِ همسایه بهروز شدند:test-stoneوtest-vat-exemptکهapplyGoodsSaleWageرا استخراج میکنند حالاfeeSaleSideهم لازم دارند، وtest-fee-bookمهرِ اتصالش ازapplyGoodsType(r, g); feeBookApply(r);بهdocFeeChainمنتقل شد.
- تست:
node scripts/test-nasie-fee.js— ۹۰ بررسی در ۷ بخش. عددها از خودِ ویدئو (سرویسِ ٪۶ دریافتی و ٪۸ فروش، فیِ قبلیِ ٪۹، تخفیفِ ٪۲٫۵ روی ۱۲٫۵۰۰ و ٪۱٫۵ روی ۲۴۰٫۲۳۰). مهمترینها: ٪۸ روی سندِ پرداخت مینشیند و روی دریافت نه؛ میانگینِ وزنی ٪۷ میدهد آنجا که «آخرین عدد» ٪۱۲ میداد؛ عددِ دفترِ فیِ ٪۱۰ مازادِ ٪۲ را دوباره نمیگیرد ولی فیِ دریافتیِ ٪۶ میگیرد؛ ردیفِ کد ۹ هم ازstkRowSubjو هم ازgpRowOkبیرون میماند وfeeRecvForبعدش همان ٪۶ را میدهد؛ و ماندهٔ طلایی از ۱۲٫۵− دقیقاً به ۱۲٫۱۸۷− میرسد.
#دفتر معین — v47
- مسئله: پنل برای «گردشِ حسابِ یک نفر» فقط
personLedgerرا داشت — یک مودالِ هفتستونه که هر سند را یک سطر میکرد. سه چیز در آن نبود و هر سه همانهاییاند که طرفِ حساب سرشان بحث میکند: ماندهٔ بعد از هر ردیف، ریزِ ردیف (سندِ پنجقلمی یک عددِ درهم میشد)، و ماندهٔ قبل از بازه. ویدئوی مرجع کلِ صحنهاش همین است: «ماندهٔ این سندشون بدهکاره؛ سند بعدی چون آبشده وزنش بیشتر بوده طلبکار شده… تا آخرین سند و ماندهٔ نهایی.» - قاعدهٔ سختِ این ماژول:
ماندهٔ نهاییِ دفتر == balances()[pid]. اگر این تساوی بشکند کاربر بین «کارت حساب» و «دفتر» گیر میکند و هیچکدام را باور نمیکند. چونbalances()= ماندهٔ اول دوره + ΣdocDelta، وdocDelta= Σ(rowMult×computeRowMag) +DIR[type] × bd.extra، خطهای دفتر هم عیناً از همان دو منبع ساخته میشوند. یعنی ردیفِ «سود فروشنده و ارزش افزوده» خطِ جدای خودش را میگیرد — وسوسهٔ «این که ردیفِ واقعی نیست، حذفش کن» دقیقاً همان جایی است که تساوی میشکند. تست این را با ۲۰۰ سناریوی تصادفی قفل میکند و یک بررسیِ منفی هم دارد:ok('بدونِ خطِ مالیات، عدد با کارت حساب فرق میکرد', …, true). - موتورِ تازهای نوشته نشد.
moDocLines(d)همانrowMult/computeRowMag/docTaxBreakdownرا صدا میزند و برای متادیتای نمایشی ازdbDirOf،dbUnitOf،dbSpecialsOf،dbDocUserوsharhLabelِ دفتر روزانه استفاده میکند. اگر موتورِ دومی نوشته میشد، روزی میرسید که دفتر معین با دفتر روزانه یکی نباشد و دو گزارشِ رسمی همدیگر را نقض کنند. - هیچ فیلترِ
DB.*اینجا راه ندارد — نهdbDocPassو نهdbRowPass. دفتر روزانه ابزارِ گشتن است و فیلتر کارش را راه میاندازد؛ دفتر معین ابزارِ تطبیق است و یک ردیفِ حذفشده یعنی یک ماندهٔ غلط. جستوجو (MO.q) استثناست چون بعد از ساختِ ماندهٔ تجمعی اعمال میشود و فقط نمایش را میبُرد. - ماندهٔ رونده روی کلِ تاریخ ساخته میشود، بعد بازه از آن بریده میشود.
moLedger(pid)کلِ خطوط را باbGold/bRial/bCoins/bCursمیسازد وmoView(pid)فقط اندیسهای داخلِ بازه را برمیدارد. برعکسش (اول ببُر، بعد جمع بزن) ستونِ مانده را از صفر شروع میکند و «ماندهٔ قبلی» هم دیگر جایی برای آمدن ندارد.prevدقیقاً ماندهٔ خطِfirst - 1است، و اگر بازه از اول باشد ماندهٔ اول دوره. endعمداً ماندهٔ کلِ حساب است، نه جمعِ پنجره. کاربر بازه را برای دیدن میگذارد، نه برای عوضکردنِ اینکه چقدر طلبکار است. اگرendجمعِ بازه بود، هر بار که کسی «این ماه» را انتخاب میکرد یک عددِ متفاوت با کارت حساب میدید و همان بیاعتمادیِ بالا برمیگشت.noشمارندهٔ همین دفتر است، نهd.code. طرفِ حساب میگوید «فاکتور سومِ من»، نه «سند ۳۷۵».dbDocNos()از قبل همین کار را برای دفتر روزانه میکرد ولی کلیدشpersonId || bankIdاست؛ اینجا چون دفتر ذاتاً تکشخصه است، شمارش داخلِ خودِmoLedgerانجام میشود و یک پیمایشِ اضافه صرفهجویی میشود.- سربرگها:
t.moeinکنارِt.docوt.drill. دفترِ معین دومین نمایی است (بعد ازpnl) که مقصدِ منو نیست و به یک موضوعِ مشخص گره خورده. پس مثل بقیه درstashActive/adoptTab/openTab/go/tabsSnapshot/tabsRestore/tabXferPutیک فیلد گرفت. بدون آن، باز کردنِ دفترِ دو نفر در دو سربرگ یعنی هر دو سربرگ آخرین شخص را نشان میدادند.tabTitleهم «معین — نام» میسازد تا در شلوغی گم نشود. - دسترسی به «اشخاص» بسته است (
canView('moein') → canView('persons'))، همان الگویی کهdocدارد: چیزی که از فهرستِ اشخاص باز میشود نباید مجوزِ سومی لازم داشته باشد، وگرنه کاربری که به اشخاص دسترسی دارد روی دکمهای کلیک میکند که همیشه خطا میدهد. personLedgerحذف شد، نه اینکه کنارش بماند. هر سه ورودیاش ([data-led]در فهرست اشخاص،#pcFullدر کارت حساب،[data-sled]در خلاصهٔ مدیریتی) بهmoOpenوصل شدند. نگهداشتنِ هر دو یعنی دو جایِ نگهداری برای یک چیز و دو عددِ ممکن برای یک سؤال. تست باhasnt(…, 'function personLedger(')جلوی برگشتش را میگیرد.- نشانها (
p.moMarks) روی خودِ شخص مینشینند، نه در یک جدولِ جدا. یک{key: 1}ساده، با کلیدِdocId#rowIndex— نه اندیسِ نمایشی، چون اندیس با هر تغییرِ بازه و جستوجو جابهجا میشود و نشان روی ردیفِ اشتباه میافتاد. وقتی آخرین کلید برداشته شود خودِmoMarksهمdeleteمیشود تا رکوردِ خالی روی شخص نماند. - چرا نشان چندتایی است و نه «تا کجا رسیدم». نسخهٔ اولِ همین کار یک بوکمارکِ تکی بود (
p.moMark). صدای ویدئوی مرجع نشان داد مدلش غلط است: کاربر ردیف یک را تیک میزند، ردیف دو را در پرینتِ طرفِ مقابل پیدا نمیکند و رد میشود، ردیف سه را تیک میزند. با نشانِ تکی، همان ردیفِ دو گم میشد — و دقیقاً همان ردیف است که اختلافِ حساب است. moMarkedTotalsرویall.rawکار میکند، نهall.lines. در حالتِ خلاصه،linesخطهای گروهشدهاند وkeyشان مصنوعی است (docId#s<unit|dir>)؛ نشانها همیشه روی کلیدِ ریز ذخیره میشوند. پسmoLedgerهر دو را برمیگرداند و جمعِ نشاندارها همیشه از ریز خوانده میشود — وگرنه روشنکردنِ کلیدِ «خلاصه» جمعِ نشاندارها را صفر میکرد.marked.goldماندهٔ اول دوره را در خودش دارد. بدونِ آن، تساویِ «همه نشان بخورند ⇒ جمعِ نشاندارها == ماندهٔ نهایی» فقط برای شخصی برقرار بود که ماندهٔ اول دورهاش صفر است — یعنی همان کاربری که این ابزار را لازم ندارد. تست این را جدا میسنجد (openGold = 7).- خطِ خلاصه وقتی نشاندار است که همهٔ ریزهایش باشند، و تیکزدنش همه را با هم میزند (
l.keys). یک منبعِ حقیقت، نه دو تا: اگر خطِ خلاصه نشانِ مستقلِ خودش را داشت، خاموشکردنِ کلیدِ «خلاصه» یک وضعیتِ متناقض نشان میداد. moGroupDocگروهبندی را درونِ یک سند نگه میدارد و ماندهٔ رونده بعد از آن محاسبه میشود. چون ردیفهای یک سند در دفتر پشتِ هماند، ماندهٔ بعد از آخرین خطِ خلاصه دقیقاً همان ماندهٔ بعد از آخرین ردیفِ ریز است. کلیدِ گروهunit|dirاست و خطهایsepLine(مالیات و اجرت) عمداً ادغام نمیشوند — همان چیزیاند که کاربر خواسته بود جدا ببیند.MO.ojratمجموع را دست نمیزند، فقط جایش را عوض میکند.c.wageازrialِ همان ردیف کم و در یک خطِ#wageجمع میشود. تست تساوی باbalances()را در این حالت هم میسنجد، چون دقیقاً همینجاست که یک اشتباهِ علامت، اجرت را دوبار حساب میکند.MO.bydateپیشفرض خاموش است و ترتیبِ پیشفرضmoDocsSortedبر اساسِd.codeاست، نه تاریخ. فاکتورهای کاغذی به ترتیبِ ثبت دستِ طرفِ حساب رسیدهاند؛ سندِ عقبافتادهای که با تاریخِ قدیمی وارد شده باید ته بماند تا ماندهٔ آخرِ دفتر با آخرین فاکتوری که دستِ اوست یکی دربیاید. ترتیب رویendاثری ندارد (جمع جابهجاییپذیر است) و تست همین را قفل میکند.MO.peerازrmtIsDocاستفاده میکند، نه ازstate.settings.remitHidePeer. آن تنظیم مالِ فاکتورِ چاپیِ مشتری است و پیشفرضش دستِ کاربر؛ دفترِ معین گزارشِ داخلی است و پیشفرضش باید همیشه پنهان باشد. دو کلیدِ جدا، چون دو مخاطبِ جدا.- یادداشتِ ردیف (
r.note) همیشه میآید ولی یادداشتِ سند (d.note) فقط باMO.docNote. یادداشتِ سند روی همهٔ ردیفهای آن سند تکرار میشود؛ اگر همیشه میآمد، سندِ شصتردیفی شصت بار یک جمله را تکرار میکرد. هر دو درmoLineTextهستند تا جستوجو ببیندشان — همان کاری که در ویدئو با جستوجوی «بررسی شد» میکند. MO.cur،MO.rialOnlyوMO.markبعد از ساختِ ماندهٔ رونده اعمال میشوند، مثلMO.q. یعنی مثل جستوجو فقط پنجرهٔ دید را میبُرند؛bGold/bRialِ هر ردیفِ باقیمانده همچنان ماندهٔ واقعیِ همان نقطه است وendهیچوقت تکان نمیخورد.- نشان روی هیچ عددی اثر ندارد — نه
moLedger، نهmoView().end، نهmoTotals.markedیک محاسبهٔ کنارِ آن است. اگر روی ماندهٔ رسمی اثر میگذاشت (مثلاً «ماندهٔ تأییدشده»)، یک عددِ رسمیِ سوم ساخته میشد و همان بیاعتمادیِ بالا برمیگشت. - کلیدِ فاصله
preventDefaultدارد. بدونِ آن هر تیک یک صفحه اسکرول میکرد و جای دست در جدول گم میشد. بعد از هر تیکmoFocus(keys)فوکوس را روی همان ردیف برمیگرداند، چونmoRerenderکلِ DOM را دوباره میسازد و بدونِ آن واخوانی با کیبورد بعد از اولین تیک قطع میشد. - دکمهٔ تیک
stopPropagationدارد وondblclickش خنثی شده. بدونِ آن، دو بار زدنِ سریعِ تیکondblclickِ ردیف را هم شلیک میکرد و وسطِ واخوانی یک سندِ بیربط باز میشد. تیک هم فقط روی:hover/:focus-withinدیده میشود تا ستونِ شماره پر از دکمه نشود. - چاپ با کلاسِ
body.mo-printing، نه با یک بلوکِ@media printتازه. بلوکِ چاپِ موجود به#docFactorPrintسنجاق است (body * { visibility: hidden }). بهجای بازنویسیِ آن — که فاکتورِ چاپی را به خطر میانداخت — دفترِ معین کلاسِ خودش را رویbodyمیگذارد و همان قاعده را برای#moPrintتکرار میکند.max-heightوoverflowِ.db-wrapهم در چاپ برداشته میشوند وگرنه فقط یک صفحهٔ اسکرولشده چاپ میشد. دکمهٔ تیک در چاپdisplay:noneاست. - ستونِ مانده در CSS با
nth-childباریک نمیشود. ردیفهای «ماندهٔ قبلی» و «ماندهٔ نهایی»colspanدارند وnth-childرویشان میلغزد و ستونِ اشتباه را میبُرد. جدول در.db-wrapاسکرولِ افقی دارد و همان کافی است — این عمدی است، نه از قلم افتاده. - ثبتهای جانبی:
<section class="view" id="view-moein">درadmin.html؛TITLES.moein؛ بلوکِ.mo-head/.mo-person/.mo-chips/.mo-chip/.mo-tbl/.mo-bcol/.mo-bal/.mo-prev/.mo-end/.mo-chk/.mo-marked/.mo-mkrow/.mo-note/.mo-sum/.mo-detail/.mo-print-headدرadmin.css. - تست:
node scripts/test-moein.js— ۱۴۳ بررسی در ۱۴ بخش. بخشِ ۱۲ دویست سناریوی تصادفی میسازد (نوع سند، عیار، مالیات، ماندهٔ اول دوره و تعدادِ ردیفِ تصادفی) و در هرکدامmoView().endرا باbalances()میسنجد. بخشِ ۱۱ سیمکشیِ سربرگها، ورودیها، CSS و همین مستند را از متنِ منبع قفل میکند. بخشِ ۱۳ چرخهٔ کاملِ نشان را میسنجد — از جمله همان تساویِ نهایی («همه نشان بخورند ⇒marked.gold == end.gold») و حالتِ منفیاش با یک ردیفِ جامانده. بخشِ ۱۴ هر شش کلیدِ نمایش را جدا میسنجد و در هر کدام دوباره تطبیق باbalances()را چک میکند.
#معکوسِ سند — ابزار Ctrl+H (v48)
- ویژگی در سطحِ سند پیاده شد، نه ردیف. نرمافزارِ مرجع «معکوس» را روی هر ردیف تعریف میکند؛ این کدبیس چنین مفهومی در سطحِ ردیف ندارد (نوعِ سند یکجا برای کلِ ردیفها تعیین میشود). پس یک سندِ کاملِ آینه ساخته میشود — با نوعِ برعکس، برای شخصِ دیگر.
revOpposite(type)تنها نگاشتِ جهت است:فروش↔خرید،دریافت↔پرداخت، وسایر → ''(بدونِ معکوسِ روشن). همانجایی که دکمه/کلید تصمیم میگیرند نمایش داده شوند یا نه.revCanDoc(d)نگهبانِ دکمه و کلید است:docIsSaved(d)(سندِ در حالِ ویرایش رد میشود)،revOpposite(d.type)غیرِ خالی،d.personIdموجود، و دستکم یک ردیف باcomputeRowMag(r) > 0. هر چهار شرط مستقل از UI دوباره درrevDoهم چک میشوند.revCloneRows(d)دیپکلون است، نه ارجاع — دستکاریِ ردیفِ کپیشده هرگز سندِ مبدأ را عوض نمیکند (تست جدا این را میسنجد). چهار فیلد عمداً حذف میشوند چون قفلکنندهٔ سندِ مبدأ بودند:note،chk،retOf،posSwipeId/posAccId.dateهم پاک میشود، نه کپی — سندِ آینه تاریخِ ذخیرهشدنِ خودش را میگیرد.revDo(d, toId)دقیقاً مثلِretDo(i,'new',…)(مرجوعی) یک پیشنویسِ ذخیرهنشده میسازد:newDoc(revOpposite(d.type))را صدا میزند، بعدpersonId/personName/priceUnit/rate/bankKind/bankId/rowsرا از سندِ مبدأ مینشاند و یادداشتی میگذارد که به کد و نامِ سندِ مبدأ اشاره میکند.persist()صدا زده نمیشود — دقیقاً مثلِ مرجوعیِ «سند جدید»، کاربر اول میبیند، بعد خودش «ذخیره سند» میزند.- سندِ آینه به سندِ مبدأ قفل نیست — برخلافِ حوالهٔ دوطرفه و کارتخوان که یک شناسهٔ مشترک دو سند را به هم میبندد، اینجا هیچ فیلدِ متقابلی رد و بدل نمیشود. سندِ مبدأ بعد از
revDoهنوز دقیقاً همان چیزی است که بود (نوع، شخص، ردیفها) — تست این را صریح میسنجد. openReverseDoc()از همان الگویdocMovePick(پنجرهٔ «کجا سند بزنم؟») استفاده میکند: هشدار +personCombo+ دکمهٔ تأییدِ افزودهشده بهصورتِ پویا.- دکمهٔ نوارِ ابزار (
#dReverse) فقط با شرطِrevOpposite(d.type) && docIsSaved(d)رندر میشود، درست کنارِ دکمهٔdMove. کلیدِ Ctrl+H (document.keydown) همان شرط را رویcurDocوdocViewActive()میسنجد؛ بدونِ این دو شرط، کلید در صفحههای دیگر یا رویِ سندِ خالی هم شلیک میکرد. - تست:
node scripts/test-doc-reverse.js— ۳۳ بررسی؛ شاملِ نگاشتِ جهت، هر چهار گیتِrevCanDocجدا (ذخیرهنشده/سایر/بدونِشخص/بدونِارزش)، کپیِ عیناً وزن و فی، حذفِ چهار فیلدِ قفلکننده و پاکشدنِ تاریخ، ایزولهبودنِ دیپکلون، و اجرای واقعیِrevDo(نوع/شخص/اعداد/یادداشت/RENDER.doc/دفترِ کارها/toast درست، و سندِ مبدأ +persist()دستنخورده).
#ماشین حسابِ سلول — کلید = (v49)
openCalc(startVal, mode, onOk)جای امضای قدیمیِ(startVal, title, isWeight, onOk)را گرفت.modeیکی از'weight'/'count'/'money'است؛ عنوان و واحد و قالبِ نمایش (wt/toFa/money) از همانmodeمشتق میشوند. در حالتِcount،total()باMath.roundگِرد میشود چون نیمدانه معنا ندارد.- کلیدِ
=حالا روی سه گروه سلول بسته میشود:input[data-k="vazn"]،input[data-k="tedad"]وinput.doc-fi. نگاشتِ ستون به حالت:vazn→weight،tedad→count، بقیهmoney. برایtedad، بعد از نشستنِ نتیجهgoldSyncUnitWeight(r)صدا زده میشود تا وزنِ جنسِ «وزنِیکعددی» همگام بماند (همان کاری کهonchangeعادی میکند). - ممیزِ بارکدِ بازار: فقط در حالتِ وزن یک چکباکس نمایش داده میشود. با روشنبودنش، ورودیِ صحیحِ بدونِ نقطه (
/^\d+$/) ÷۱۰۰ میشود (بارکدهای بیممیزِ بازار:533 → 5.33). عددِ دارای ممیز دستنخورده میماند، و روی حالتِ تعداد اصلاً اعمال نمیشود. حالتِ چکباکس درstate.settings.calcBcمیمانَد و باpersist()ذخیره میشود. - حافظهٔ ترکیب: اگر ≥۲ ورودی داشتیم،
onOkعلاوه بر مقدار یکmemo = {n, text}هم میگیرد؛ فراخوان آن را درr.calcMemo[k]مینشاند (کلید همانvazn/tedad/fi). یک ورودی یا هیچ ورودی →memo = nullو کلید پاک میشود.onchangeِ عادیِ سلول همr.calcMemo[k]را حذف میکند، پس هر ویرایشِ دستی حافظه را باطل میکند (دو منبعِ حقیقت نمیماند). calcMemoBadge(r, k)نشانِ کوچکِΣnرا کنارِ سلولِ وزن/تعداد/مبلغ رندر میکند؛titleاش ریزِ زنجیره را نشان میدهد. بدونِ حافظه رشتهٔ خالی برمیگرداند.
#ماشین حسابِ سلول — ضرب/تقسیم، F2، بازیابیِ نوار (v51)
بازبینیِ کاملِ ویدئوی مرجع چهار رفتارِ دیگر را نشان داد که در v49 پیاده نشده بود. همه روی همان openCalc سوار شدند، بدونِ شکستنِ امضای قبلی:
- زنجیرهٔ چهار عملگر: ورودیها از
{op:'+'|'-'}به{op: '+'|'-'|'*'|'/'}گسترش یافت (CALC_OPS/CALC_OPTXT/CALC_OPCLSسه ثابتِ ماژولاند تا تست هم از همانها بخواند).total()دیگر یکreduceِ جمع نیست، بلکه زنجیرهٔ چپبهراست است: موردِ اول مقدارِ آغازین (با-منفی) و بقیه بهترتیب اعمال میشوند — بدونِ تقدمِ ضرب بر جمع، دقیقاً مثلِ نوارِ ماشین حسابِ رومیزی.(۲+۳)×۴ = ۲۰. تقسیم بر صفر no-op است (t = v ? t / v : t). حاصلِ غیرِcountباround(t*1e6)/1e6از نویزِ ممیزِ شناور پاک میشود. - عملگرِ قابلِ تعویض: هر برچسبِ نوار یک دکمهٔ
data-copدارد که عملگرِ همان مورد را درCALC_OPSمیچرخانَد — بهجای حذفوورودِ دوباره. F2برای تأیید:confirmCalc()هم به دکمهٔ فوتر بسته است، هم بهkeydownِ#calcInp، هم به یکdocument.keydown(برای وقتی فوکوس روی ورودی نیست). شنوندهٔ سراسری با پرچمِliveو شرطِ باز بودنِ#modalBackمحافظت و درdone()برداشته میشود تا بعد از بستهشدنِ پنجره شلیک نکند.confirmCalcاگر عددی در ورودی مانده باشد اول با عملگرِ در انتظار (pendOp) ثبتش میکند — پس عددِ آخر جا نمیمانَد (همان رفتاری که در ویدئو۳ × ۸٫۱۳۳ → F2را کار میاندازد).- بازیابیِ نوار:
openCalcپارامترِ چهارمِ اختیاریseedگرفت و فراخوانِ کلیدِ=حالاr.calcMemo && r.calcMemo[k]را پس میدهد.memoعلاوه بر{n, text}یکentries: [{op, val}]هم دارد؛ باseed.entriesنوار عیناً بازسازی میشود. حافظههای قدیمیِ v49 (بیentries) بهسلامت به همان رفتارِ «یک مقدارِ آغازین» برمیگردند، پس migration لازم نیست. - پاک کردنِ آخری + بازگشت:
undoیک پشتهٔ snapshot است؛snap()قبل از هر جهش (افزودن، حذفِ تکی، حذفِ آخری، تعویضِ عملگر) کپیِ آرایه را میگذارد وundoLast()آن را برمیگرداند. دو دکمهٔ#calcDel/#calcUndoروی نوارِ خالی/پشتهٔ خالیdisabledمیشوند. - برچسبِ دکمهٔ تأیید از
ico('check') + ' تأیید'به متنِ سادهٔ'✓ تأیید (F2)'تغییر کرد، چونopenModalبرچسب را باtextContentمینشانَد و مارکآپِ SVG آنجا عیناً بهصورتِ متن دیده میشد. - CSS: کلاسهای
.calc-chip.times/.calc-chip.divide(بنفش/آبی) و.calc-op.times/.calc-op.divide، دکمهٔ.calc-chip .cop، و ردیفِ.calc-tools— با معادلِ تمِ تاریک..calc-rowحالاflex-wrapدارد چون چهار دکمهٔ عملگر کنارِ ورودی مینشیند. - تست:
node scripts/test-calc.js— ۷۳ بررسی؛ با یک DOMِ کمینه (بهعلاوهٔdocumentِ شبیهسازیشده برای F2) واقعاًopenCalcرا میراند: سه حالت، گِردشدنِ تعداد، ممیزِ بارکد، ماندگاریِcalcBc، ساخت/نبودِ حافظه،calcMemoBadge، سیمکشیِ=روی سه ستون، و همهٔ رفتارهای v51 —۳×۸٫۱۳۳=۲۴٫۳۹۹،۲۴٫۳۹۹÷۳=۸٫۱۳۳، چپبهراست بودنِ زنجیره، تقسیم بر صفر، کلیدهای*//،F2، بلعیدنِ عددِ ثبتنشده، بازیابیِ نوارِ چهارموردیِ ویدئو، سازگاری با حافظهٔ قدیمی، و چرخهٔ پاککردن/بازگشت.
#شمارهٔ دوم و تصفیه با متفرقه (v50)
- شمارهٔ دوم: فیلدِ آزادِ
d.no2(پیشفرض'') روی سربرگِ سند، کنارِd_code/d_date— ورودیِid="d_no2"باonchangeکهd.no2 = toEn(this.value).trim()را مینشانَد. در هیچ محاسبهای خوانده نمیشود؛ فقط با سند ذخیره و نمایش داده میشود (تطبیقِ دستی با فاکتورِ طرف). - تصفیه با متفرقه:
goldSettleQuick()— همتای دقیقِdiscQuick/دSettleAllبرای ماندهٔ طلایی بهجایِ نقدی:ng = personBalanceExcl(d.personId, d.id).gold + docDelta(d).gold— ماندهٔ طلاییِ زندهٔ سند، همان عددی که در کارتِ «طلایی» نشان داده میشود.- وزنِ لازم:
w = round(abs(ng), 3). ردیفِ تازه:{ kind:'gold', tashkhis: ng>0?'خروج':'ورود', sharh:'2', desc:'متفرقه', babat:'تصفیه', vazn:w, ayar: state.settings.karatBase, fi:0 }. - جهت با تشخیصِ مطلق (
خروج→rowMult= −۱،ورود→+۱) بسته میشود، نه باDIR[d.type]— دقیقاً همان دلیلی که «کسر و اضافه» ازgiveاستفاده میکند نه از نوعِ سند: اینطوری در فروش/خرید/دریافت/پرداخت/سایر یکسان درست کار میکند. - چون
ayar = karatBaseوayarCalcخالی است،rowW750(r) === vazn؛ پس اثرِ ردیف روی مانده دقیقاًmult × wاست و باngکاملاً خنثی میشود (اثباتِ عددی در تست). - بدونِ
personIdیا باabs(ng) < 0.001کاری نمیکند و پیامِ راهنما میدهد؛ مثلِdiscQuick. - دکمهاش (
id="dGoldSettle") درست کنارِ کارتِ ماندهٔ طلایی، با همان کلاسهایdf-actions ks-actions/btn ghost ks-quickکه برای کدِ ۸ ساخته شده بودند — بدونِ نیازِ به CSSِ تازه. - تست:
node scripts/test-gold-settle.js— ماندهی طلبکار/بدهکار، خنثیشدنِ کاملِ مانده پس از افزودنِ سند به دفتر، استقلال از نوعِ سند (سایر)، گِردشدنِ سهرقمی، و رفتار روی ماندهٔ صفر/بدونِ طرف حساب.
#مرجوعیِ شناسنامهدار — v52
ویدئوی مرجع هشت دقیقه است. نصفِ چیزی که نشان میدهد از قبل پیاده بود و ممیزیِ کد پیش از هر تغییری همین را گفت: «مرجوع شود» (data-ret)، میانبرِ Ctrl+R، پنجرهٔ «همین سند یا سندِ جدید؟» (retAsk)، پیوندِ retOf و retOfChip، و فیلدهای refiner/receipt همه از v20/v44 موجود بودند. کارِ تازه شناسنامهدار کردنِ مرجوعی است: انتخابگرِ منبع، نگهبانِ کجثبت، دو زندگینامه، و وضعیتِ مشتقِ «موجود برگشتی».
- مدل دست نخورد: مرجوعی همچنان
r.tashkhis === 'مرجوع'است، نه یک نوعِ سندِ تازه. وسوسهاش هست، چون ویدئو دو اسمِ مستقل دارد («دریافت مرجوعی»/«پرداخت مرجوعی»)، ولی آن دو اسم فقط دو ترکیب از چیزیاند که داریم: «دریافتِ مرجوعیِ» کیمیا = سندِ پرداخت + تشخیصِ مرجوع (rowMult = +1)، و «پرداختِ مرجوعیِ» او = سندِ دریافت + مرجوع (−1). فیزیک یکی است و فقط لنگرِ نامگذاری فرق دارد. نوعِ سندِ تازه یعنی دستبردن درrowMult، کاردکس، فاکتور و سود و زیان — همه برای یک تغییرِ صرفاً لفظی.retMoveWord(d, r)همان دو اسم را از رویrowMultمیسازد و فقط جایی که کاربر میبیند (زندگینامه و فاکتور) به کار میرود.
retSrcScanیک فرمولِ جهت دارد و همان یک خط هر دو کاربرد را میگیرد:want = -rowMult(d, r). منبعِ یک برگشت همیشه ردیفی است که جهتش وارونهٔ خودِ این ردیف باشد — چیزی که رفته باید برگردد. نسخهٔ اولِ کدDIR[d.type]را ثابت میگرفت؛ برای ردیفِ مرجوعی درست بود (جهتش−DIR، پس منبعش+DIR) ولی برای ردیفِ عادیای که نگهبانِretMisfiledواردش میکند (جهتش+DIR) وارونه بود و نگهبان هیچوقت چیزی پیدا نمیکرد. تستِ بخشِ ۶ همین را افشا کرد. سه فیلترِ دیگر هم روی فهرست است و هر سه عمدیاند: فقطx.personId === d.personId، فقطleft > RET_EPS(آنچه کاملاً برگشته دیگر پیشنهاد نمیشود)، و همخانوادگیِretSrcFam(طلا با طلا، چک با چک) تا فهرستِ چک پر از آبشده نشود.
- مرجوعیِ جزئی از
retSrcDone(docId, ri)میآید و در هیچ فیلدی ذخیره نمیشود. هر بار کلِ اسناد پیمایش و ردیفهایی کهretOfبه همان ردیف دارند جمع میشوند. پرچمِ ماندگار («این ردیف نصفش برگشته») یعنی یک عددِ دوم که میتواند با واقعیت واگرا شود — مثلاً وقتی سندِ مرجوعی حذف یا ویرایش شود. همین قاعده روی «موجود برگشتی» هم هست:chkPapersوضعیت را از تاریخچهٔ حرکتِ برگه مشتق میکند وc.statusتازهای نمیسازد.
retSrcMatchدو شکل از پرسش را امتحان میکند، نه یکی.RET_KBنگاشتِ سه ردیفِ کیبورد است (۳۱ کلید، شاملِ;→ک و'→گ) وretKbFaصورتِ فارسیِ متنِ لاتین را میسازد. اگر فقط صورتِ ترجمهشده جستوجو میشد، متنِ واقعاً لاتین (نامِ بانکِ لاتین، کدِ انگلیسی) قربانی میشد؛ پس هر دو شکل تست و اجتماعشان گرفته میشود.retSrcNormهم پیش از تطبیق، ارقامِ فارسی،ي/كعربی، ZWNJ و جداکنندهٔ هزار را یکدست میکند — بدونِ آخری، «۱،۲۵۰،۰۰۰» که کاربر از صفحه کپی میکند هیچوقت با1250000جور نمیشد.
RET_KBعمداً یک شیء است، نه دو رشتهٔ موازی. نسخهٔ اولvar RET_KB_EN = 'qwerty…;'بود و تستِ اسکریپت را میشکست: استخراجکنندهٔgrab(name,'var')درscripts/test-*.jsآگاه از رشته نیست و روی اولین;ِ عمقِ صفر میایستد — که وسطِ رشته افتاده بود. آکولادِ شیء عمق را بالای صفر نگه میدارد و مسئله را ریشهای میبندد. هرvarِ سطحِ بالای تازهای که مقدارش رشتهای شاملِ;باشد همین دام را دارد.
retSrcApplyبرخلافِretCloneRowفیلدِchkرا کپی میکند، و این تفاوت عمدی است.retCloneRowعمداً چک را میاندازد چون یک چکِ تازه میسازد؛ ولی مرجوعیِ شناساییشده لفظاً همان برگهٔ کاغذی است و دفتر چک باید بتواند بشناسدش.status: 'برگشتی'وretOf: 1هم همینجا مینشیند. برای آبشده همcondOpen/condBase/condAnsپاک و شرحِ ۳ به ۱ برمیگردد: مرجوعیِ یک لُنگه دیگر «شرطی» نیست، عیارش قبلاً معلوم شده.
chkList()بازسازی نشد، فقط دو فیلد گرفت (ret,retOf). ساختارِ ورودیهایش در چند فایلِ تستِ دیگر قفل است (test-check-book,test-status-board)؛chkPapers()لایهٔ گروهبندی روی همان خروجی است وchkPaperKey(no, bank)هویتِ برگهٔ فیزیکی را میسازد. تستْ صریحاً مهر میزند که «کلیدهای قدیمیِchkListسرِ جایشاناند».
retMisfiledهشدار است نه سد، و درsaveDocنیست. بندِ «بازبینی سند» برای چیزی است که باید پیش از ثبت تصمیم بگیری؛ این یکی باید کنارِ خودِ ردیف دیده شود. شرطِ برخوردش سختگیرانه است تا کاذب نشود: برای طلا هملُنگهبودن (condRowKey === condLotKey) و برابریِ وزن تاRET_EPS؛ برای چک همشمارهبودن و برابریِ مبلغ. وزنِ برابر تعمداً شرط است — همان لُنگه با وزنِ متفاوت میتواند واقعاً خریدِ تازه باشد. دکمهٔdata-misfixتشخیص را «مرجوع» میکند و پیوند را میبندد، و همان لحظه هشدار خاموش میشود (تست این چرخه را کامل میسنجد).
- بازهٔ پیشفرضِ «شناسنامهٔ آبشده» یک ماه است و این تصمیمِ عملکردی است، نه سلیقه.
goldLotGroup()کلِstate.docsرا میپیماید و ویدئو خودش میگوید بازهٔ باز گزارش را کُند میکند.GL_RANGESچهار گزینه دارد (۳۰/۹۰/فقط برگشتخورده/از ابتدا) و هویتِ لُنگه همانcondLotKey(refiner, receipt)ِ v44 است — ردیفِ بیریزگیری یا بیقبض اصلاً وارد گروه نمیشود.
- ثبتهای جانبی: انتخابگر با الگوی موجودِ زیرردیف رندر میشود (
retSrcRowHtmlهمشکلِchkRowHtml/condRowHtml، باdata-rsrowکه مثلِdata-chkrowنشانگرِ ردیف است نه دکمه — درACCEPTED_DATAِlint-refs.jsثبت شد)؛ رنگِ خانوادگیِ بنفش (#6d4bb5) انتخاب شد تا با طلاییِ «شرطی» و آبیِ «چک» قاطی نشود؛factorRowDescحالا جملهٔ کاملِ مرجوعی را با شناسهٔ لُنگه/چک مینویسد و در چاپ سیاه و ضخیم میشود؛ برچسبِ کشv=20260818b.
- تست:
node scripts/test-ret-src.js— ۱۲۳ بررسی در ۱۱ بخش. مهمترینها: نگاشتِ نامِ ویدئو به مدلِ ما (پرداخت + مرجوع = +1)؛ فهرست فقط طرفِ حسابِ خودی و فقط جهتِ وارونه؛ جستوجو با قبضِ فارسی، دو واژهٔ همزمان، وlghdvd→ ملایری؛ مرجوعیِ جزئی که بارِ دوم فقط ماندهٔ باقی را پیشنهاد میدهد؛ نگهبانی که آتش میکند و با یک کلیک خاموش میشود؛ زندگینامهٔ سهحرکتیِ چک (دریافت ← پرداخت ← دریافت مرجوعی) که «موجود برگشتی» از آن مشتق میشود؛ و مرزها — خودارجاعی، ردیفِ تخفیف، وزنِ صفر، سندِ بیطرفحساب و سندِ «سایر» هیچکدام منبع نمیسازند.
#تسویه با آبشده — v56
- همتای چندتاییِ
goldSettleQuick، نه جایگزینش.goldSettleQuickیک ردیفِ متفرقهٔ ساختگیِ عیارِ پایه با وزنِ لازم میسازد؛openMeltSettle()از موجودیِ واقعیِstate.inv.meltsچند لُنگه برمیدارد. هر دو دکمه پای سند کنارِ هماند و شرطِ مشترکِabs(gsBal) >= 0.001دارند؛ دکمهٔ آبشده شرطِ اضافیِmeltAvailLots().lengthهم دارد، پس فقط وقتی انبار آبشده دارد دیده میشود. - جهت مطلق و همیشه «خروج».
meltLotRow(lot)هر لُنگه را{ kind:'gold', tashkhis:'خروج', sharh: meltLotSharh(lot), desc: lot.type, babat:'تسویه با آبشده', vazn: lot.weight, ayar: lot.karat||karatBase, note: meltLotTag(lot) }میکند. آبشده همیشه از مغازه بیرون میرود، پس برخلافِgoldSettleQuick(که جهت را از علامتِngمیگیرد) اینجا جهت ثابت است — و چونrowMultبرای «خروج» همیشه −۱ است، در هر نوعِ سندی یکسان مینشیند. - معادلِ ۷۵۰ منبعِ واحد است.
meltLotW750(lot) = weight × (karat||karatBase) / karatBase. هم انتخابِ خودکار، هم کارتِ باقیمانده و هم جمعِ پایین از همین میآیند؛ عیارِ خالی رویkaratBaseمیافتد تا لُنگهٔ بیعیار صفر حساب نشود. meltAutoPick(lots, target)حریصانه و بدون سرریز است. لُنگهها از سنگین به سبک مرتب میشوند و هر کدام کهmeltLotW750(l) <= rem + epsباشد برداشته میشود.target <= 0(طرف بدهکار یا صفر) یعنی هیچ لُنگهای خودکار تیک نمیخورد و انتخاب به کاربر واگذار میشود. سرریزنکردن عمدی است — تهماندهٔ مثبت را بعداً میشود با «تصفیه با متفرقه» بست، ولی بدهکارکردنِ ناخواستهٔ طرف با یک لُنگهٔ بزرگ برگشتپذیر نیست.meltLotSharh(lot): شرطی (lot.conditionalیا نوعِ حاویِ «شرطی») →'3'؛ نوعِ حاویِ «متفرقه» →'2'؛ وگرنه'1'. همان کدهای شرحِ آبشدهاند تا لُنگه در کاردکس و شناسنامه درست بنشیند.- موجودی روی apply دست نمیخورد. مثلِ بقیهٔ ثبتها فقط ردیفِ سند ساخته میشود؛ کمشدنِ لُنگه از انبار از مسیرِ عادیِ کاردکس/دفتر ذوب دنبال میشود — سازگار با فلسفهٔ موجودیِ دستی + تطبیقِ کاردکسِ برنامه.
- پنجره:
openMeltSettleازopenModal(..., wide)استفاده میکند؛ جستوجو باnormSearch(همان ترجمهٔ فارسی/لاتین و بیاعتنا به جداکنندهٔ هزار)، تیکِ «انتخاب همه» روی نتایجِ همان جستوجو کار میکند، وpaintDynamicکارت و جمعِ پایین را زنده بهروز میکند. CSSِ تازه زیرِ نشانِv56درadmin.css(.ms-wrap,.ms-target,.mst-rem.pos/neg/zero,.ms-row.on, …). - تست:
node scripts/test-melt-settle.js— معادلِ ۷۵۰ (عیارِ خالی هم)، نگاشتِ کدِ شرح، فیلترِ لُنگههای وزندار، برچسبِ قبض/ریزگیری، انتخابِ خودکارِ حریصانه/بدونسرریز/هدفِ ≤۰، و شکلِ ردیفِ خروجی. برچسبِ کشv=20260819b.
#سندِ عقبتاریخ (جامونده) — v57
- نتیجه از قبل وجود داشت؛ این افزوده فقط آگاهسازیِ پیشدستانه است. چیدمانِ دفترها از دیرباز بر اساسِ تاریخ است —
dbDocsSorted()دفتر روزانه را باjord(date)و سپسtsمرتب میکند وmoDocsSorted()وقتیMO.bydateروشن است همین کار را برای دفتر معین میکند. پس سندِ دیرثبتشده خودش سرِ جای تاریخش مینشیند؛ کارِ v57 فقط این است که کاربر این را ببیند و نگرانِ دستکاریِ شمارهٔ سند نشود. docBackAnchor(d): سندی «عقبتاریخ» است اگر سندِ دیگری با کدِ کوچکتر ولی تاریخِ جلوتر وجود داشته باشد (num(x.code) < num(d.code) && jord(x.date) > jord(d.date)). خروجیnullیا{ next }است کهnextنزدیکترین سندِ تاریخاً بعدی (با tie-break روی کد) است تا پیام «قبل از سندِ فلان» بسازد. سندِ بیتاریخ و اولین سند هرگز عقبتاریخ نیستند.dbBackSet(): یکبار رویstate.docsمیگردد و{docId:1}برای همهٔ عقبتاریخها میسازد؛ جدولها بهجای صدازدنِdocBackAnchorدر هر ردیف از این نقشه میخوانند.- جای نمایش:
docBackdateHtml(d)راهنمای زیرِ کادرِ تاریخ در ویرایشگرِ سند را میسازد و با تغییرِ تاریخ زنده بهروز میشود ($('dBackdate').innerHTML = docBackdateHtml(d)درonchange). درdbTableHtmlهمیشه و درmoTableHtmlفقط وقتیMO.bydateروشن است، چیپِ.db-backکنارِ.db-codeمیآید. - بدونِ تغییرِ داده. هیچ فیلدی به سند اضافه نمیشود و شمارهٔ سند دست نمیخورد؛ این صرفاً یک لایهٔ نمایشیِ مشتق از تاریخ و کدِ موجود است. CSSِ تازه زیرِ نشانِ
v57درadmin.css(.doc-backdate,.db-backبا variantِ تیره). - تست:
node scripts/test-backdate.js— سناریوی خودِ ویدئو (سندهای ۳/۴/۵ بهترتیب و سندِ ۶ به تاریخِ عقب)، تشخیصِ «قبل از سندِ ۴»، مجموعهٔ تکعضویِ عقبتاریخ، و مرزها: سندِ بیتاریخ، تاریخِ برابر، و سندِ اول. برچسبِ کشv=20260819c.
#ماندهٔ سنگ و نگین — v60
- مسئله: موتورِ سنگِ v28 کامل بود و v34 دفترِ مادّهٔ همراه را ساخت، ولی
matrLedgerصریحاً نگین را بیرون میگذارد (if (!matrOn(r)) return;) و فقط یک مبلغِ ریالی را دنبال میکند. برای نگین این کافی نیست: نگین سه بُعد دارد — قیراط، دانه و مبلغ — و در دو ارز خرید و فروش میشود. پس هیچ جای پنل نمیگفت «چقدر عقیق و فیروزه در ویترین مانده». stoneRaw(r)ازstoneRial(r)جدا شد.stoneRialهمچنان معادلِ ریالیِ لحظهای را باLIVE.dollarمیسازد و رفتارش موبهمو دستنخورده ماند (تستِtest-stone.jsهمان را قفل میکند)؛stoneRawمبلغ را در ارزِ خودش برمیگرداند. دفترِ انبار رویstoneRawبسته میشود، چون اگر روی معادلِ ریالی بسته میشد ماندهٔ پارسال هر روز با نرخِ زندهٔ امروز بازنویسی میشد.stoneLedger(period)مشتق است، نه ذخیرهشده — دقیقاً به همان دلیلِmatrLedger: نگین موجودیتِ مستقلِstate.inv.goodsنیست، روی ردیفِ طلا سوار است. جهتِ ورود/خروج از همانrowMult(d, r)ِ همیشگی میآید، پس «مرجوع» و «تشخیصِ مطلق» خودبهخود درست مینشینند و منطقِ جهتِ دومی نوشته نشد.- کلیدِ گروهبندی
name + cur + unitاست، نه فقط نام. یاقوتِ دلاری و یاقوتِ تومانی دو ماندهٔ جدا هستند؛ جمعزدنشان عددی میسازد که هیچ معنایی ندارد.stoneLeftByCur(period)هم جمعِ هر ارز را جدا میدهد و تومان را اول میچیند. - پرچمِ خطا (
e.bad) به روشِ قیمتگذاری وابسته است — و این مهمترین تصمیمِ این نسخه است. نسخهٔ اولِ پیادهسازی هر ماندهٔ مبلغِ منفی را خطا میگرفت؛ غلط بود. برای نگینِ قیراطی، بالا بردنِ فی (خرید ۱۷۳٫۹۱ دلار بر قیراط، فروش ۱۸۰) کارِ درست است و طبعاً ماندهٔ مبلغِ منفی میسازد که همان سود است. پسe.amtOnlyدنبال میشود (آیا همهٔ ردیفهای این سنگmode === 'amount'بودهاند؟) و بر اساسش:amtOnly→left < 0خطاست؛ وگرنه →leftW < -1e-6 || leftQ < -1e-6خطاست. matrCostWarnِ ردیفبهردیف برای نگین تکرار نشد. ردیفِ نگین اغلب چند دانه را با هم میآورد (دوازده لیبل در یک ردیف)، پس میانگینِ خریدِ هر دانه معیارِ بیثباتی است و هشدارِ دروغ میسازد. ابزارِ صادقانه همان دفتر است بهعلاوهٔ تطبیقِ خودِ کاربر با لیبلِ کارهای مانده.- راهنمای داخلِ فرم (
#st_warn) از ثابت به مشتق تبدیل شد. متنِ قبلی به همهٔ روشها میگفت سود را بیرون از قیمتِ سنگ بگذار، که برای نگینِ قیراطی خلافِ واقع است. حالاsync()درstoneForm()متن را ازmodeو پرچمِmatrمیسازد: مادّه/فقطمبلغ → «سود را روی اجرت»، قیراطی/دانهای → «سود را در فیِ هر قیراط». هشدار لحظهٔ ورودِ داده دیده میشود، چون بعد از ثبتِ سند کسی برنمیگردد نگاه کند. - جای نمایش:
stoneLedgerHtml()درinvTblGoods()پیش ازmatrLedgerHtml()رندر میشود و اگر دفتر خالی باشد رشتهٔ خالی برمیگرداند. CSSِ تازه زیرِ نشانِv60درadmin.css(.stl-led,.stl-sums,.stl-chip,.stl-cur,.stl-bad,.stl-warn) با تکیه بر متغیرهای موجودِ--gold-soft/--red-soft. - بدونِ تغییرِ داده و بدونِ migration: هیچ فیلدی به
r.stoneاضافه نشد؛ کلِ این قابلیت لایهای مشتق ازstate.docsاست. - تست:
node scripts/test-stone-stock.js— ۵۶ بررسی در ۱۱ بخش، شاملِ بازسازیِ عددبهعددِ سناریوی ویدئو (۱۲ انگشترِ ۲٬۳۰۰٬۰۰۰ ← فروشِ ۵۰٬۰۰۰ → ماندهٔ ۲٬۲۵۰٬۰۰۰؛ و حالتِ غلطِ ۱۰۰٬۰۰۰ → ۲٬۲۰۰٬۰۰۰)، یاقوتِ ۲٫۳ قیراطیِ دلاری (ماندهٔ وزنِ صفر و ماندهٔ مبلغِ ۱۴٫۰۱− دلار بدونِ هشدار)، کسریِ واقعیِ قیراط (ماندهٔ ۱٫۲− و با هشدار)، تفکیکِ ارز، و مرزها (مادّه، سنگِ بینام، سندِ «سایر»، مرجوعی). برچسبِ کشv=20260820a.
#مشتریان تک — v61
- مسئله: یک حسابِ مشترک برای مشتریانِ گذری لازم است (وگرنه فهرستِ طرف حسابها پر از نامِ یکبارمصرف میشود)، ولی همین حساب یک تناقض میسازد: نامِ حساب عمومی است و روی فاکتور چاپ میشود، در حالی که گیرندهٔ هر فاکتور فرق دارد. پس هویت از حساب جدا شد: حساب یکی، هویت روی هر
doc. - ماهیتِ نُهم، نه یک پرچمِ بولی.
walkinبهACC_NATURESاضافه شد تا در همان ماشینِaccNatureبنشیند و نقطهٔ تصمیمِ تازهای ساخته نشود. عمداً هیچ رفتاری تحمیل نمیکند — برخلافِretail، نهpriceUnitرا به گرم میبَرد نهtaxOnرا روشن میکند. دلیلش خودِ ویدئو است: بنکداری که به گذری هم میفروشد سودش روی اجرت است نه درصدِ تکفروشی، و اجبارِ گرم خطای گِرد کردن میسازد.docNatureFieldHtmlهم چون بهdocIsRetailAcctبند است، خانهٔ «قیمت هر گرم» روی این سند اصلاً ساخته نمیشود. d.recvNidتنها فیلدِ تازه است.recvNameوrecvTelاز قبل روی سند بودند؛ فقط کد ملی اضافه شد و به هر سه سازندهٔ سند و بهHIST_DOC_FIELDSوصل شد تا تغییرش در «تاریخچه کارها» ثبت شود. هیچ migration لازم نیست: نبودِ فیلد در سندِ قدیمی همان''است.recvPeople()مشتق است، نه ذخیرهشده — به همان دلیلِmatrLedger/stoneLedger: یک فهرستِ موازیِ ذخیرهشده روزی با اسناد ناهمخوان میشود (سند پاک شود، املا اصلاح شود) و آنوقت دو حقیقتِ رسمی داریم. کلیدِ یکتایی بهترتیب تلفن → کد ملی → نامِ نرمالشده است تا همان یک نفر که یکبار با تلفن و یکبار بیتلفن ثبت شده دو نفر نشود. تازهترین سند حرفِ آخر را دربارهٔ املای نام میزند و فیلدِ خالی هیچوقت جای فیلدِ پرشده را نمیگیرد.- تکمیلِ خودکار با
datalistروی هر سه خانه، نه یک کامپوننتِ انتخابگرِ تازه.recvLookup(q)اول با رقم (تلفن یا کد ملی، حداقل ۴ رقم تا برخوردِ تصادفی نشود) و بعد با نامِ دقیق میگردد؛recvBindبقیهٔ خانهها را پر میکند ولی چیزی را که کاربر خودش نوشته بازنویسی نمیکند (همنامیِ دو مشتری واقعی است). repaint()فقط#dRecvWarnرا مینویسد، نهRENDER.doc(). رندرِ دوبارهٔ کلِ ویرایشگر وسطِ تایپ فوکوس را میدزدد.- باگی که همینجا درست شد: چاپِ فاکتور
d.recvNameرا جای نامِ حساب میگذاشت. روی حسابِ مشترک این یعنی فاکتور با دفتر نمیخوانَد. حالاcustNameنامِ حساب است وviaNameبا برچسبِ «توسط:» کنارش میآید (.mln-viaدر سربرگ،.mln-via-bدر نوارِ جعبه)؛ اگرnormSearchهر دو یکی باشد «توسط» چاپ نمیشود. walkinBook(pid, q)واحدش فاکتور است نه ردیف — همان تفاوتی که این نما را از دفترِ معین جدا میکند. جستوجو باnormSearchروی[name, tel, nid, code, no2]کار میکند و مرتبسازی تاریخِ نزولی سپس کدِ نزولی است.walkinBookHtmlسقفِ ۴۰ ردیف دارد و فقط وقتی رندر میشود کهpersonNature(p) === 'walkin'و حساب سند داشته باشد. حالتش درMO.recvQاست — عمداً جدا ازMO.q، چون آن یکی ردیفهای دفتر را فیلتر میکند و یکیکردنشان نصفِ دفتر را زیرِ دستِ کاربر ناپدید میکرد.- دو هشدارِ صادق بهجای یک تشخیصِ ناممکن. «دو مشتری در یک سند» مستقیماً قابلِ تشخیص نیست (ردیفها گیرنده ندارند)، پس
walkinDocWarnدو نمایندهٔ صادق دارد:noname(گیرنده خالی) وcrowded(بیش ازWALKIN_ROWS_MAX = 12ردیفِ پُر). آستانه عمداً بلند است — هشدارِ زودهنگام کاربر را به بیاعتنایی عادت میدهد. ردیفِ خالی شمرده نمیشود وnonameبرcrowdedمقدم است. - جای نمایش:
recvRowHtml(d)درRENDER.docجای سه فیلدِ درونخطیِ قبلی نشست؛walkinBookHtml(MO.pid)درRENDER.moeinبلافاصله بعد ازmoChipsHtml(vw). آیکنِ تازهٔidcardبهICONاضافه شد. CSSِ تازه زیرِ نشانِv61درadmin.css(.recv-walkin,.recv-warn.rw-noname|.rw-crowded,.wb-panel,.wb-count,.wb-warn,.wb-tbl,.wb-anon,.wb-none,.mln-via,.mln-via-b) با حالتِ تیره و موبایل؛ کارت در@media printبسته میشود. - تست:
node scripts/test-walkin.js— سناریوی خودِ ویدئو (خانم صانعی/میرعالمی/رهنما روی کدهای ۴۴۱ تا ۴۴۵)، یکتاییِ گیرنده با تلفن، جستوجو با نام و موبایل و کد ملی و کد سند و شمارهٔ دوم، هر دو هشدار با مرزِ دقیقِ ۱۲/۱۳، و اینکهwalkinمثلِ بنکداری رفتار میکند نه تکفروشی.test-acc-nature.jsهم به نُه ماهیت بهروز شد. برچسبِ کشv=20260820c.
#مرکز افزونهها — v72
- رابط مرجع بازطراحی شد، نه کپی. پنجرهٔ فشرده و قدیمیِ ویدئو به یک صفحهٔ مستقل و واکنشگرا تبدیل شد: معرفی کوتاه، شمارندهٔ وضعیتها، جستوجو، فیلتر و کارتهای هماندازه. تصویر ویدئو فقط ساختار محصول را تعیین کرد؛ رنگ، فاصلهگذاری، سلسلهمراتب، وضعیتهای متنی و حالت تاریک با سیستم طراحی فعلی پنل هماهنگ شدند.
ADDON_CATALOGمنبع واحد تعریف افزونههاست. نام، گروه، آیکن SVG، توضیح، امکانات، طول آزمایش، افزونهٔ همراه و شغل پیشنهادی در یک کاتالوگ ثابت نگهداری میشوند. UI و منطق وضعیت هر دو از همین آرایه میخوانند تا متن کارت و پنجرهٔ جزئیات از هم واگرا نشوند.addonBaseStateباaddonStateجدا است. اولی وضعیت مستقیم مجوز را میخواند؛ دومی وابستگی بسته را اعمال میکند. به همین دلیل «حساب سکه و ارز» وقتی «آبشدهفروشی» فعال یا آزمایشی است، بدون دستکاری رکورد خودش وضعیتincludedمیگیرد. خاموششدن بسته نیز آن را به وضعیت واقعی خودش برمیگرداند.- دورهٔ آزمایشی قابل تکرار نیست.
trialAtحتی پس از انقضا باقی میماند وaddonStartTrialشروع دوباره را رد میکند. پایان دوره ازexpiresAtمشتق میشود و روز باقیمانده با سقف روزانه نمایش داده میشود؛ شمارندهٔ جدا و قابلواگرایی ذخیره نشده است. - خرید شبیهسازی نمیشود.
addonRequestPurchaseفقط وضعیتpendingو زمان درخواست را ثبت میکند. نه مبلغی کم میشود و نه وضعیتownedبهصورت محلی جعل میشود. متن اعتماد پایین صفحه و پیام موفقیت نیز همین مرز را صریح میگویند. - فعالسازی شغل دفتر گیت مستقل دارد.
addonApplyJobفقط برای افزونهٔownedیا دورهٔtrial، فقط افزونهٔ دارایjobو فقط دفترِ نوشتنی کار میکند. تغییر باlogActionثبت و از مسیر عادیpersistذخیره میشود؛ دفتر بایگانی هرگز تغییر نمیکند. - دسترسی و ناوبری: مقصد
addonsبهALL_VIEWS،TITLES، منوی کناری و<section id="view-addons">اضافه شد تا در همان مدل دسترسی و سربرگهای پنل کار کند. آیکنها همگی از مجموعهٔ SVG داخلیاند و ایموجی ساختاری استفاده نشده است. - واکنشگرایی و دسترسپذیری: جستوجو برچسب خوانا دارد، فیلترها
role="group"دارند، وضعیت با متن و نقطه نمایش داده میشود، فوکوس صفحهکلید مشخص است، هدفهای اصلی حداقل ۴۲ پیکسل ارتفاع دارند، در عرض کوچک کارتها و جزئیات تکستونه میشوند وprefers-reduced-motionحرکت کارت را حذف میکند. - کش و راهنما: برچسب فایلهای
admin.cssوadmin.jsبهv=20260827aتغییر کرد. همین سند منبع راهنمای کاربر است و باnode scripts/build-rahnama.jsبهpublic/rahnama.htmlتبدیل میشود. - تست:
node scripts/test-addons.js— کاتالوگ، وضعیت پایه، بستهٔ آبشده/سکهوارز، یکبارمصرفبودن آزمایش، ثبت درخواست بدون فعالسازی جعلی، گیت شغل دفتر، سیمکشی منو/صفحه، CSS واکنشگرا و متن راهنما را بررسی میکند.
#تسویه فردایی و پولی حواله — v73
- ماندهٔ فردایی جدول جداگانه نیست.
forwardBalances()فقط اسناد دارایd.forwardرا از مسیر رسمیdocDelta()جمع میکند. سند عادی در این مانده وارد نمیشود و حذف یا اصلاح سند، نتیجه را همان لحظه تغییر میدهد؛ بنابراین منبع موازی و قابلواگرایی وجود ندارد. - علامتگذاری روی خود سند است. کلید
#d_forwardفقطd.forwardرا ذخیره میکند و برای اسناد قدیمی نبودن فیلد معادل خاموش است؛ migration لازم نیست. مقصدforwardدرALL_VIEWS،TITLES، منو و بخش مستقل صفحه به مدل دسترسی موجود متصل شده است. - تسویه از موتور حسابداری عبور میکند.
forwardSettle()برای هر شخص سند «سایر» با دو ردیفِ دارای تشخیص مطلق میسازد: طلای هماندازه و خلاف علامتِ مانده، سپس پول همعلامتِ مانده.rowMultوcomputeRowMagهمان اثر را بهdocDeltaمیدهند؛ محاسبهٔ دوم یا دستکاری مستقیم مانده نداریم. - ردپای حسابرسی کامل است.
forwardSettlementشاملbatchId، مظنه، فی مشتقشدهٔ هر گرم و ماندهٔ طلای پیش از تسویه است. ردیفها «فی تصفیه» دارند، هر شخص فقط به اندازهٔ ماندهٔ باز خودش تسویه میشود و پس از صفرشدن دیگر کاندید نیست. - صندوق جاری عمداً بیرون است. سند تسویه
cashId،bankKindوbankIdخالی دارد و نوعش «سایر» است؛ فقط ماندهٔ شخص را از طلا به پول تبدیل میکند. دفتر بایگانیشده نیز درforwardSettleرد میشود. - پولی حواله کد ۷ از همان مدل جفتسند استفاده میکند.
cashRemittanceForm()یک خرید و یک فروش باremitIdمشترک، نقشهایfrom/to، اشارهگر طرف مقابل وcashRemitمیسازد. هر دو ردیفsharh: '7'دارند و در گزارش ویژهٔ حواله طبقهبندی میشوند. - همگامسازی هنگام ذخیره است.
syncCashRemitDoc()پس از نشستن نسخهٔ ویرایششده درstate.docsاجرا میشود و وزن، عیار، فی، تاریخ، شرح و نام طرف را روی جفت مقابل مینشاند؛ ساخت سند یتیم پیش از عبور از اعتبارسنجی اتفاق نمیافتد. - رابط و دسترسپذیری: فهرست فردایی فیلتر گروه، انتخاب چندتایی با
aria-pressed، انتخاب همه، جمع زنده و پیشنمایش دارد. کنترلها با متن و نه فقط رنگ وضعیت را میگویند، فوکوس قابلمشاهده است، موبایل تکستونه و حرکت درprefers-reduced-motionخاموش میشود. رنگها از توکنهای فعلی و آیکنها از SVG داخلیاند. - کش و راهنما: برچسب
admin.cssوadmin.jsبهv=20260827bرسید و راهنمای HTML از همین Markdown تولید میشود. - تست:
node scripts/test-forward-settlement.js— مشتقبودن مانده، حذف سند عادی، تبدیل دقیق طلا به پول، صفرشدن مانده، نبود اتصال صندوق، metadata حسابرسی، سیمکشی کد ۷، همگامسازی، ناوبری، CSS و مستندات را بررسی میکند.
#چرخهٔ روزانهٔ دفتر فردایی — v74
- مرحله روی سند است، نه روی یک جدول موازی.
forwardStageOf(d)سه وضعیتfuture،todayوcashرا میخواند. سندهای v73 کهforwardStageندارند با همانd.forwardبهعنوانfutureشناخته میشوند؛ سند تسویهٔ قدیمی نیز ازforwardSettlementبهcashمیرود، پس migration اجباری وجود ندارد. - مرز روز صریح است.
forwardEligibleDoc(d, 'future')فقط سندی را میپذیرد که تاریخش قبل ازtodayJalali()باشد. در نتیجه معاملهٔ فرداییِ امروز حتی اگر برای همان شخص باشد با ماندهٔ فرداییِ دیروز جمع نمیشود. سند قدیمیِ بدون تاریخ برای جلوگیری از گیرکردن داده همچنان قابل انتقال است. - فردایی به امروزی اثر مالی ندارد.
forwardPromote()فقط اسناد انتخابشده و واجد شرایط را باforwardEvent()بهtodayمیبرد. وزن و مبلغ و ردیفها دستنخوردهاند؛ یکbatchIdمشترک، زمان، کاربر، مسیر تبدیل و عبارت «فردایی به امروزی» به سند اضافه میشود. - امروزی به نقدی مرحلهٔ حسابداری است.
forwardSettle()حالا فقط خروجیforwardBalances('today')را میپذیرد، سندهای مبدأ را بهcashمیبرد و سند دو ردیفی فی تصفیه را باfrom: todayوto: cashمیسازد. اجرای دوباره روی همان مانده ممکن نیست، چون سند مبدأ دیگر در صفtodayنیست. - جستوجو و حسابرسی از دادهٔ خود سند تغذیه میشوند.
forwardEventsآرایهای الحاقی است وforwardEventمتن فارسی مسیر را بهd.noteاضافه میکند؛ بنابراین جستوجوی فعلی دفتر روزانه بدون ایندکس یا گزارش دوم، «فردایی به امروزی» و «امروزی به نقدی» را پیدا میکند.forwardHistory()نیز همین رویدادها را برای تب تاریخچه مرتب میکند. - رابط سهمرحلهای: سه تب با
role=tabوaria-selected، شمارندهٔ مستقل، راهنمای متناسب با مرحله، فیلتر گروه، انتخاب چندتایی و CTA یکتای هر مرحله دارد. تاریخچه زمان و کاربر و سند را نشان میدهد؛ در موبایل تبها و رویدادها تکستونهاند و فوکوس وprefers-reduced-motionحفظ شده است. - کش و آزمون: برچسب منابع به
v=20260827cرسید.test-forward-settlement.jsعلاوه بر محاسبات v73، جداسازی امروز/دیروز، سازگاری سند قدیمی، هر دو انتقال، رویداد الحاقی، جلوگیری از تسویهٔ دوباره، متن قابل جستوجو و رابط سهتب را بررسی میکند.
#تطبیق اصطلاحات فی تصفیه و پولی حواله — v75
- اصطلاح قدیمی بدون ابهام حفظ شده است. عملی که در آموزش قدیمی با دکمهٔ «پولی شود» انجام میشد، در رابط جدید با CTA صریح «فی تصفیه و انتقال به نقدی» نمایش داده میشود. منطق مالی تغییر نکرده است:
forwardSettle()همان ماندهٔ طلایی انتخابشده را با مظنه به ردیف پولی تبدیل میکند؛ فقط چرخهٔ v74 الزام میکند ابتدا سندهای روز قبل به مرحلهٔtodayبرسند. - کد ۷ در نقطهٔ اقدام دیده میشود. متن دکمهٔ سند از «پولی حواله» به «پولی حواله · کد ۷» تغییر کرد تا کاربر بدون اتکا به tooltip همان تشخیص حسابداری آموزش را ببیند. مدل جفتسند، همگامسازی و عدم اثر روی صندوق دستنخوردهاند.
- طراحی و دسترسپذیری: CTA اصلی همچنان یک دکمهٔ متنی با آیکن SVG، وضعیت
disabledواقعی و هدف لمسی مناسب است. انتخاب چندحسابی از کنترلهایaria-pressedاستفاده میکند و برخلاف فهرست دسکتاپ قدیمی به نگهداشتن Ctrl وابسته نیست؛ بنابراین روی موبایل و صفحهکلید نیز همان عملیات قابل انجام است. - کش، راهنما و آزمون: برچسب منابع به
v=20260827dرسید، راهنمای HTML از Markdown بازسازی شد و آزمون تخصصی وجود عبارتهای جدید در رابط، دکمهٔ کد ۷ و مستندات تطبیقی را کنترل میکند.
#ورود پایدار به پنل ادمین — v76
- علت پرش:
tabsRestore()آخرین سربرگ فعال را بدون توجه به نوع ورود بازمیگرداند. اگر آخرین سربرگsmartبود، ورود تازه به/adminبهظاهر پنل را به اتوماسیون میفرستاد؛ درحالیکه پاسخ HTTP خود مسیر ادمین درست بود. - ورود و رفرش از هم جدا شدند. نوع navigation با Navigation Timing خوانده میشود. ورود تازه به
/adminیا/admin.htmlبدون query، داشبورد را بهعنوان صفحهٔ فعال بهtabsRestore(forceView)میدهد؛ درreloadهمان سربرگ فعال قبلی حفظ میشود و?view=...نیز همچنان مقصد صریح خودش را باز میکند. - هیچ کار بازیابیشدهای حذف نمیشود. اگر سربرگ داشبورد از قبل وجود داشته باشد همان فعال میشود؛ در غیر این صورت یک سربرگ داشبورد به میز افزوده میشود. سربرگ دستیار هوشمند و هر سند ذخیرهنشده سر جای خود باقی میمانند.
- کش و آزمون: منابع به
v=20260827eرسیدند. آزمون سربرگها، ورود اجباری به داشبورد، حفظ سربرگ هوشمند، جلوگیری از داشبورد تکراری و رفتار عادی بازیابی در refresh را کنترل میکند.
#ورود مستقیم و امن به پنل ادمین — v77
- نبود نشست دیگر کاربر را از پنل خارج نمیکند. مسیر
/adminدر صورت نبودauthTokenبه صفحهٔ اصلی اتوماسیون هدایت نمیشود و فرم «ورود به پنل ادمین» را در همان صفحه نشان میدهد. - ورود از احراز هویت اصلی سامانه انجام میشود. فرم نام کاربری و رمز عبور را با
POST /api/auth/loginبررسی میکند. فقط حسابی که مجوزsettingsدارد پذیرفته میشود؛ توکن حساب بدون مجوز در مرورگر ذخیره نمیشود. - مقصد ورود مشخص است. پس از ورود موفق، پنل با
/admin?view=dashboardباز میشود تا بازیابی سربرگ قبلی کاربر را به دستیار هوشمند نبرد. - انقضای نشست داخل پنل مدیریت میشود. پاسخ
401توکن منقضی را پاک میکند و پیام ورود دوباره میدهد؛ پاسخ403نیز پیام نداشتن اجازه را در همان فرم نمایش میدهد. هیچکدام کاربر را به اتوماسیون منتقل نمیکنند. - کش و آزمون: منابع به
v=20260827fرسیدند. آزمون رگرسیون، فرم ورود بدون توکن، endpoint ورود، کنترل مجوز تنظیمات، ذخیرهٔ توکن، مقصد داشبورد، مدیریت401/403و حذف ریدایرکت قدیمی به/را کنترل میکند.
#گزارش روز و مقصد امن چرخهٔ فردایی — v78
- رفتار آموزش به مدل امن تبدیل شد. در نرمافزار مرجع، کاربر برای جلوگیری از انتخاب اشتباه باید در اطلاعات پایه مقصد «فردایی → امروزی» و «امروزی → ریال» را تنظیم کند. این پنل از ابتدا مقصد را از مرحلهٔ فعال مشتق میکند؛ تب
futureفقطforwardPromote()و تبtodayفقطforwardSettle()را اجرا میکند. نشانfw-route-lockهمین مقصد قفلشده را قبل از اقدام آشکار میکند و تنظیم موازی یا قابلواگرایی ساخته نشده است. - گزارش امروز در خود چرخه است.
forwardHistPeriodپیشفرضtodayدارد و سه کارت، کل تبدیلهای امروز و تعداد هر مسیر را ازforwardHistory()مشتق میکنند. هیچ شمارندهٔ جداگانهای ذخیره نمیشود. - فیلترها قابل ترکیباند.
forwardHistoryFiltered(rows, period, route, query)بازهٔ امروز/همه، مسیرfuture-todayیاtoday-cashو جستوجوی نام شخص، شماره سند، یادداشت، کاربر و نام مرحله را همزمان اعمال میکند. ورودی جستوجو فقط فهرست را تازه میکند تا فوکوس و متن تایپشده از بین نرود. - ردپای حسابرسی حفظ شده است. کارت هر رویداد شماره سند، تاریخ سند، کاربر، مسیر و زمان دقیق را نشان میدهد. داده همچنان از
forwardEventsخود سند میآید و دفتر روزانه نیز عبارت مسیر را ازd.noteجستوجو میکند. - واکنشگرایی و دسترسپذیری: گروههای فیلتر
role="group"و دکمههاaria-pressedدارند، جستوجو برچسب خوانا دارد، فوکوس صفحهکلید مشخص است و کارتهای آمار و کنترلها در موبایل تکستونه میشوند. - کش و آزمون: منابع به
v=20260827gرسیدند. آزمون تخصصی، حذف رویداد قدیمی از نمای امروز، مسیر دقیق، جستوجوی شماره سند، ترکیب فیلترها، وجود مقصد امن و سیمکشی رابط گزارش را کنترل میکند.
#پنل تسویهٔ ریالی و حوالهٔ مرحلهای — v79
- منبع مانده موازی ساخته نشد.
rialPanelRows()از همانbalances()وdocDelta()سراسری استفاده میکند. حالت ریال مستقیم فقطb.rialرا میخواند و حالت خالص درrialNetValue()معادل ریالی طلا را باmarketRial()، سکه را با وزن و عیارcatalog.coinTypesو دلار را باLIVE.dollarبه همان مانده اضافه میکند. ارز بدون نرخ زنده عمداً وارد خالص نمیشود و اصل ماندهاش دستنخورده میماند. - فیلتر گروه و جستوجو pure هستند. شناسهٔ گروه، حالت خالص و عبارت جستوجو ورودی
rialPanelRows(groupId, useNet, query)است. خروجی مثبت به ستون طلبکار و خروجی منفی به ستون بدهکار میرود و با قدر مطلق مبلغ مرتب میشود. - حساب مقصد تعهد است، نه سند. رکوردهای سبک در
state.rialTransfersشامل شخص، بانک، حساب، صاحب حساب، سقف درخواست، یادداشت و آرایهٔpaymentsهستند. افزودن حساب مقصد هیچ تغییری درstate.docsنمیدهد و سقف مبلغ آن از خالص مثبت شخص بیشتر نمیشود. - سند فقط از فیش تأییدشده ساخته میشود. ثبت هر پرداخت، مبلغ را به کمترِ ماندهٔ درخواست و بدهی خالص پرداختکننده محدود میکند، سپس با همان مدل حوالهٔ v18 یک سند
پرداختبرای طلبکار و یک سنددریافتبرای بدهکار باremitIdمشترک میسازد.rialRequestIdرابطهٔ هر دو سند با حساب مقصد را برای حسابرسی نگه میدارد. - تقسیم و تکمیل قابل حسابرسی است.
rialRequestPaid()جمع پرداختهای مرحلهای را مشتق میکند وrialRequestDone()با رسیدن جمع به سقف، وضعیت کامل را خودکار برمیگرداند.manualDoneفقط صف پیگیری را دستی میبندد و برای مانده سند جعلی نمیسازد. حساب مقصد دارای پرداخت نیز تا بررسی اسناد مرتبط حذف نمیشود. - رابط واکنشگراست. دسکتاپ دو ستون متقارن، کارت تفکیک مانده و فهرست وضعیت حواله دارد؛ زیر ۱۰۰۰ پیکسل ستونها و زیر ۶۴۰ پیکسل کارتها و عملیات تکستونه میشوند. وضعیت کامل/ناقص علاوه بر رنگ با متن و آیکن بیان میشود.
- کش و آزمون: منابع به
v=20260827hرسیدند.test-rial-panel.jsمحاسبهٔ ریال، طلا، سکه و دلار، علامت طلبکار/بدهکار، فیلتر گروه و جستوجو، پرداخت مرحلهای، تکمیل خودکار، سیمکشی نما، سقف امن و ساخت اسناد مرتبط را کنترل میکند.
#رفتار درج خودکار حواله و مرز سند — v98
rmtEligibleDoc()فقط سند همنوع، همتاریخ و بدونprintedAtیاclosedAtرا قابل الحاق میداند.remitAlwaysNewDocبا مقدار پیشفرضfalseبرای دادههای قدیمی نیز سازگار است.- هر طرف حواله مستقل انتخاب میشود؛ در صورت الحاق، ردیف با
remitIdوremitRoleخودش روی سند مینشیند و در صورت نبود سند واجدشرایط، همان جفت سند جدید قبلی ساخته میشود. این کار از سند یتیم یا تکرار حواله جلوگیری میکند. rmtIsDoc()و چاپ فاکتور هم فرمت قدیمیِ شناسهٔ سند و هم ردیفهای حوالهٔ الحاقشده را میشناسند. چاپ سند با ثبتprintedAt، سند را برای حوالهٔ بعدی از حالت باز خارج میکند.- تنظیمات و توضیح کاربر در همان صفحهٔ RTL و با کارت رفتار سند ارائه شدهاند؛ کلید کش منابع روی
20260831cقرار گرفته است.
#راهنمای دیداری انتخاب ویژهٔ دفتر روزانه — v97
renderDailyBook()بر اساس برش فعال، کارت راهنمای کوتاه و مستقل از دادهٔ مالی نمایش میدهد: حوالهها، یا گزارش متمرکز کارتخوان، یا سایر انتخابها.- فیلترهای بازه، جهت حواله و دستگاه/نوع کارتخوان همچنان ورودیهای جدا هستند و با هم اعمال میشوند؛ کارت فقط وضعیت انتخاب فعلی را برای جلوگیری از برداشت اشتباه روشن میکند.
- خلاصهٔ کارتخوان دریافت کارتی، بازگشت، تسویهشده و در انتظار تسویه را جدا نگه میدارد. هیچ شمارنده یا سند جدیدی برای این راهنما ذخیره نمیشود.
.db-guideبا tokenهای پوسته، RTL، حالت تیره، موبایل و متن توضیحی خوانا طراحی شده و به حرکت یا مرورگر وابسته نیست.
#تسویهٔ قالکاری و محاسبهٔ کسری سختشده — v84
- پیش از قالکاری، ماندهٔ کسری تمام بخشهای کارگاه را یادداشت و کنترل کنید. در ذوب و آبشده ← دفتر ذوب یک قبض تازه بسازید و نوع آن را قالکاری کارگاه قرار دهید.
- هر بخش کارگاه را در یک ردیف جدا با شرح، وزن طلب و عیار ثبت کنید. جمع وزن، عیار میانگین و معادل ۷۵۰ بهصورت زنده محاسبه میشود؛ بنابراین خاک، پوستوپرداخت و تراشکاری با عیارهای متفاوت قاطی نمیشوند.
- پس از برگشت قالکاری، از «ثبت ری» وزن شمش واقعی، عیار آزمایشگاه، شماره قبض و کارمزد را وارد کنید. اختلاف معادل ۷۵۰ مورد انتظار و شمش برگشتی بهعنوان افت یا سرک نهایی همان دوره نمایش داده میشود.
- در حالت قالکاری، محاسبهگر عیار هدف پنهان میشود چون هدف این فرآیند ساخت ترکیب نیست؛ هدف، تطبیق طلب کارگاه با شمش واقعی برگشتی است.
- با گزینههای ثبت خروجی میتوان شمش را به موجودی آبشده و اجرت قالکاری را به مخارج افزود. برای بستن ماندهٔ هر بخش کارگاه، سند تسویه را با شرح «بابت قالکاری» روی همان حساب ثبت کنید تا سابقهٔ هر بخش حفظ شود.
- برای هر دورهٔ قالکاری یک قبض مستقل بسازید؛ این کار کسری سختشده، کارمزد و شمش برگشتی هر دوره را جدا و قابل حسابرسی نگه میدارد.
#چرخهٔ آزمایش، خرید دائمی و ارتقای افزونهها — v85
- رفتار ویدئو به مدل شفاف محصول تبدیل شد. مرکز افزونهها اکنون برای دورهٔ ۳۰ روزه نوار پیشرفت و روز باقیمانده دارد و CTA «مدیریت دوره و خرید» روشن میکند که خرید هم در میانهٔ آزمایش و هم پس از پایان آن ممکن است.
- دسترسی خریداریشده صریحاً دائمی است. وضعیت
ownedبا برچسب «فعال دائمی» نمایش داده میشود و جزئیات توضیح میدهد که افزونه در حساب ثبت شده و نیاز به خرید دوباره ندارد. درخواست خرید همچنان فقطpendingمیسازد و دسترسی یا پرداخت محلی جعل نمیکند. - مرز نسخهٔ پایه روشن شد. خرید و فروش سادهٔ سکه و ارز وابسته به افزونه نیست؛ کارت و پنجرهٔ «حساب سکه و ارز» توضیح میدهند که این افزونه مخصوص حساب تفصیلی، مانده و گزارش معاملهگران سکه، صرافیها و معاملات فیزیکی یا پولی است.
- بسته و ارتقا دوبارهفروشی نمیشوند. آبشدهفروشی همچنان حساب سکه و ارز را شامل میشود. اگر رکورد مستقیم
coinfxدر وضعیتownedباشد،addonUpgradeSource()روی کارت و جزئیات پیشنهاد ارتقا نشان میدهد وaddonRequestPurchase()درخواست را باrequestKind: upgradeوcreditFrom: coinfxثبت میکند تا مابهالتفاوت هنگام تأیید محاسبه شود. - طراحی مدرن و دسترسپذیر است. نوار دوره، یادداشت مرز نسخهٔ پایه و کارت ارتقا با متن و آیکن SVG داخلی ساخته شدهاند؛ رنگ تنها حامل معنا نیست، چیدمان زیر ۶۰۰ پیکسل تکستونه میشود و حرکتهای قبلی همچنان از
prefers-reduced-motionپیروی میکنند. - کش و آزمون: منابع به
v=20260829fرسیدند.test-addons.jsاکنون پیشرفت دوره، دائمیبودن خرید، خرید حین آزمایش، تشخیص ارتقا، metadata مابهالتفاوت، متن نسخهٔ پایه، CSS واکنشگرا و مستندات v85 را کنترل میکند.
#چاپ، تخصیص و رهگیری لیبل بارکد — v86
- لیبل منبع مالی تازه نیست. رکوردهای
state.barcodeLabelsوزن، عیار، قیمت اختیاری، چیدمان، وضعیت و ارتباط باgoodsIdرا نگه میدارند؛ ساخت و چاپ لیبل بهstate.docsیا وزن ردیف موجودی دست نمیزند. - ظرفیت چاپ مشتق میشود.
labelAllocated()فقط وزن لیبلهایactiveرا جمع میکند وlabelRemaining()آن را از وزن فعلی قلم کم میکند. ایجاد وزن صفر، منفی یا بیشتر از مانده رد میشود؛ ابطال و تعویض با خارجکردن نسخهٔ قبلی از حالت فعال، ظرفیت را آزاد میکنند. - تاریخچه پاک نمیشود. ابطال وضعیت
voidو تعویض وضعیتreplaced، زمان و کاربر را روی رکورد قبلی مینشانند. نسخهٔ جایگزین کد تازه و پیوندreplacesدارد؛ اگر ساخت نسخهٔ تازه شکست بخورد، نسخهٔ قبلی به حالت فعال برمیگردد. - اسکن با موجودی موجود یکپارچه است. کد فرزند یکتا از بارکد اصلی و شمارندهٔ سهرقمی ساخته میشود.
goodsByBarcode()ابتدا لیبل فعال را بررسی میکند و سپس بارکد اصلی را؛ بنابراین اسکن در ثبت سند همان قلم واقعی را برمیگرداند و لیبل باطلشده قابل فروش نیست. - چاپ داخلی و واکنشگراست.
barcode.jsپیش از پنل بارگذاری میشود و Code 128 را بدون CDN تولید میکند. چاپ تکنسخه یا نسخهٔ کالا/صندوق، شمار چاپ و زمان آخرین چاپ را ثبت میکند. رابط در موبایل تکستونه، در حالت کاهش حرکت بدون گذار، و در دفتر بایگانی برای عملیات تغییردهنده قفل است. - کش و آزمون: منابع به
v=20260829gرسیدند.test-barcode-labels.jsتخصیص، جلوگیری از اضافهتخصیص، یکتایی کد، اسکن، ابطال، تعویض، قفل دفتر، چیدمان چاپ، سیمکشی رابط، CSS و مستندات v86 را کنترل میکند.
#اتصال، آزمون و ورودی سراسری بارکدخوان — v87
- اتصال سختافزاری جعل نمیشود. مرورگر شناسهٔ فیزیکی پورت USB را در اختیار صفحه نمیگذارد؛
scannerCfg()فقط وضعیت راهاندازی، نام دلخواه، کد اتصال، زمانها و شمار اسکن موفق را درstate.settings.scannerنگه میدارد. رابط صریحاً سازگاریUSB HID Keyboardو نیاز به پسوندEnter / CRرا توضیح میدهد. - راهاندازی سه دروازه دارد.
scannerSetupOpen()ابتدا سرعت ورود و Enter پایانی را با یک بارکد واقعی میسنجد، سپس Code 128 اختصاصیKIMIA-…را با کتابخانهٔ داخلی نمایش میدهد و فقط در صورت دریافت همان کد اتصال را فعال میکند. مرحلهٔ آخر بارکد کالا را ازgoodsByBarcode()میسنجد؛ کد اتصال یا تست هیچ سند، کالا یا موجودی نمیسازد. - اسکن سند به فوکوس وابسته نیست.
scannerGlobalKeydown()در حالت capture، رشتهٔ سریع صفحهکلید را تا Enter جمع میکند. فقط وقتی صفحهٔ سند فعال و کد به کالای واقعی یا لیبل فعال منتهی شود، متن اسکنشده را از ورودی دارای فوکوس پاک وdocScanBarcode()را اجرا میکند. ورودیهای اختصاصی بارکد از این مسیر مستثنا هستند تا دوبار اجرا نشوند؛ تایپ عادی و کد ناشناخته نیز بهعنوان کالا مصرف نمیشوند. - بازاتصال و قطع اتصال کمخطرند. اتصال دوباره توکن نرمافزاری را تازه میکند و قطع اتصال فقط capture سراسری را خاموش میکند؛
state.inv.goods،state.barcodeLabelsوstate.docsدستنخوردهاند. رخداد اتصال و قطع در دفتر بایگانی عملیات ثبت میشود و آخرین اسکن و شمار موفق برای عیبیابی قابل مشاهدهاند. - رابط مدرن و دسترسپذیر است. کارت وضعیت، ویزارد مرحلهای، نتیجهٔ زنده با
aria-live، فوکوس مشخص، دکمههای حداقل ۴۴ پیکسل، حالت تاریک، چیدمان تکستونهٔ موبایل وprefers-reduced-motionپیادهسازی شدهاند. وضعیت با متن و آیکن همراه است و به رنگ تنها متکی نیست. - کش و آزمون: منابع به
v=20260829hرسیدند.test-barcode-scanner.jsپیکربندی پیشفرض، توکن اتصال، تشخیص ورودی سریع، جلوگیری از دوبارهخوانی کادر اختصاصی، پاککردن فقط کد اسکنشده، شمارندهها، ویزارد، CSS واکنشگرا و مستندات v87 را کنترل میکند.
#چرخهٔ فروش، مرجوعی و تطبیق لیبل بارکد — v88
- شناسه روی ردیف سند میماند.
docScanBarcode()برای لیبل، آرایهٔbarcodeRefsشاملlabelId، کد، قلم موجودی و وزن را روی ردیف پیشنویس میگذارد. حالتseparateهر لیبل را جدا و حالتgroupedفقط لیبلهای همنام و همعیار را جمع میکند؛ شناسههای حسابرسی در تجمیع حذف نمیشوند. - پیشنویس وضعیت مالی نمیسازد.
labelSyncLifecycle()فقط پس از اعتبارسنجی و نشستن سند درstate.docsاجرا میشود. این تابع رخدادهای فروش و مرجوعی همهٔ اسناد را میخواند و وضعیتactive،soldیاreturnedو پیوندهایsoldDocIdوreturnedDocIdرا بازسازی میکند؛ بنابراین حذف ردیف از پیشنویس یا ذخیرهنشدن سند، لیبل را قفل نمیکند. - فروش تکراری در دو لایه متوقف است. هنگام اسکن لیبل
sold، پنجرهٔ وضعیت خریدار، تاریخ و سند مبدأ را نشان میدهد و کالا به ردیف اضافه نمیشود.labelDocIssues()نیز پیش از ذخیره، تکرار شناسه در همان سند، استفادهٔ دوباره در سند دیگر، مصرف لیبل باطل/تعویضشده و مرجوعی با مبدأ نادرست را رد میکند. - مرجوعی مدل موازی ندارد. برای لیبل فروختهشده، عملیات «افزودن مرجوعی» از
retCloneRow()موجود استفاده میکند تا فی، عیار، اجرت، سنگ و سایر قیمتگذاریهای فاکتور مبدأ عیناً حفظ وretOfبه همان سند متصل شود. پس از ذخیره، وضعیتreturnedیعنی همان شناسه دوباره آمادهٔ فروش است. - چاپ مجدد و تطبیق از تاریخچه جدا نمیشوند.
labelPrint()برای لیبل فروختهشده یا مرجوعشده همان کد را دوباره چاپ میکند و شمار چاپ را بالا میبرد؛ تعویض فقط برای لیبل آماده مجاز است. مرکز لیبل سند فروش را باز میکند و کارت تطبیق، لیبلهای آماده را به گردش موجودی همان قلم وصل میکند تا فروش دستیِ بدون اسکن تعیینتکلیف شود. - رابط دسترسپذیر و واکنشگراست. انتخاب روش چنداسکن، تراشهٔ شناسهها، هشدار فروش تکراری، کارت سند مبدأ و تطبیق موجودی با SVG داخلی، متن وضعیت، فوکوس قابل مشاهده، هدف لمسی ۴۴ پیکسل در موبایل، حالت تاریک و
prefers-reduced-motionپیاده شدهاند. - کش و آزمون: منابع به
v=20260829iرسیدند.test-barcode-sales.jsنگهداری شناسه، همگامسازی پس از ذخیره، جلوگیری از فروش دوباره، مرجوعی متصل، تجمیع قابل حسابرسی، چاپ مجدد، تطبیق موجودی، CSS واکنشگرا و مستندات v88 را کنترل میکند.
#انبارگردانی بارکدی و تعیینتکلیف اختلافها — v89
- نشست شمارش snapshot دارد.
state.barcodeStocktakesنشستهایcounting،reviewوclosedرا نگه میدارد.stocktakeStart()شناسهٔ لیبلهایactiveوreturnedدر دامنه را درexpectedثابت میکند؛scannedوresolvedجدا هستند و نشست باز باstocktakeOpenSession()پس از بستن پنجره ادامه پیدا میکند. - اسکن idempotent و خودکار ذخیره میشود.
stocktakeScan()فقط شناسهٔ داخل snapshot را میپذیرد، تکرار همانlabelIdرا رد میکند و پس از هر خواندنpersist()را اجرا میکند.stocktakeMetrics()تعداد و وزن انتظار و اسکن، وزن موجودی فاقد لیبل فعال و اختلاف تعداد دفتر با شمار لیبلها را محاسبه میکند؛ هشدار این اختلافها عمداً مانع عملیات نیست. - هیچ مورد گمشدهای بینتیجه بسته نمیشود.
stocktakeMissing()موارد اسکننشده و حلنشده را برمیگرداند وstocktakeFinish()تا خالیشدن این فهرست نشست را درreviewنگه میدارد. تعویض ازlabelReplace()موجود استفاده میکند تا شناسهٔ قبلی باقی بماند و لیبل تازه ساخته شود. - فروش دستی به سند واقعی متصل میشود. نتیجهٔ
saleشمارهٔ سند فروش را باfeeSaleSide()کنترل میکند و فقط یک ردیف همنامِ فاقدbarcodeRefsرا میپذیرد. سپس همان شناسه روی ردیف قرار میگیرد وlabelSyncLifecycle()وضعیت فروختهشده و سند مبدأ را از مدل مشترک اسناد بازسازی میکند. - کسری واقعی سند حسابداری دارد. نتیجهٔ
shortageابتدا لیبل را باطل و سپس ازadjApply()برای کمکردن وزن و در صورت وجود تعداد استفاده میکند. شناسهٔ سند اصلاح روی نتیجهٔ نشست میماند؛ در نتیجه کسری با تغییر خام موجودی یا حذف لیبل پنهان نمیشود. - رابط دادهمحور و دسترسپذیر است. نوار پیشرفت، سه KPI تعداد و وزن، هشدار اختلاف، نتیجهٔ زندهٔ اسکن با
aria-liveو فهرست عملیات سهگانه با متن و SVG داخلی پیاده شدهاند. حالت تاریک، فوکوس صفحهکلید، هدف لمسی ۴۴ پیکسل، چیدمان موبایل وprefers-reduced-motionپوشش داده شدهاند. - کش و آزمون: منابع به
v=20260829jرسیدند.test-barcode-stocktake.jssnapshot، resume، اسکن تکراری و خارج دامنه، KPI وزن و تعداد، سه مسیر تعیینتکلیف، جلوگیری از پایان زودهنگام، حسابرسی، UI، CSS و مستندات v89 را کنترل میکند.
#راهنمای هوشمند انتخاب سطح افزونه — v90
- پیشنهاد از وضعیت واقعی دسترسی آگاه است. برای سکه و ارز، فعال یا شامل بسته بودن دسترسی و دورهٔ آزمایشی در متن و CTA لحاظ میشود. برای آبشدهفروشی، مالکیت قبلی سکه و ارز با
addonUpgradeSource()تشخیص داده و مسیر ارتقا با اعتبار مابهالتفاوت نشان داده میشود. - نسخهٔ پایه عمداً CTA خرید ندارد. راهنما روشن میکند که خرید و فروش معمول سکه و ارز بدون افزونه باز است. انتخاب مسیر فقط
ADDON_UI.adviceرا تغییر میدهد و هیچ مجوز، پرداخت، شغل دفتر یا رکورد حسابداری را خودکار نمیسازد. - رابط مرحلهای و دسترسپذیر است. سه انتخاب با
aria-pressed، نتیجه باaria-live، آیکن SVG داخلی، فوکوس قابل مشاهده و هدف لمسی مناسب ساخته شدهاند. در عرض ۸۰۰ پیکسل گزینهها و CTA تکستونه میشوند، حالت تاریک از tokenهای موجود پیروی میکند وprefers-reduced-motionگذارها را حذف میکند. - کش و آزمون: منابع به
v=20260829lرسیدند.test-addons.jsمنطق پیشنهاد پایه، پیشنهاد تخصصی، تشخیص بسته و ارتقا، سیمکشی انتخابگر، واکنشگرایی، دسترسپذیری و مستندات v90 را کنترل میکند.
#نمای یکنگاه تراز طلا و سکه — v93
balExposure()روی همان منبع حقیقتbalDocs()،balLedger()وrowMult()سوار است؛ بنابراین بازه، جهت مرجوعی و ورود/خروج مطلق با دفتر تراز قدیمی دو منطق جدا ندارند.balCoinGold750()تعداد سکه را با وزن واحد و عیار همان نوع در کاتالوگ به گرم ۷۵۰ تبدیل میکند. حالتgoldcoinاین مقدار را با خالص طلای اسناد جمع میزند، حالتcoinتعداد نوع انتخابی و حالتallcoinمعادل تعداد سکهٔ امامی را برمیگرداند.- سکهٔ امامی مستقل از ترتیب کاتالوگ مبنای حالت همهٔ سکههاست؛ اگر تعریف نشده باشد اولین نوع کاتالوگ استفاده میشود و نام مبنای واقعی در رابط نمایش داده میشود.
balExposureDetail()برای حالت طلا ردیفهای دفتر طلا، برای حالت سکه ردیفهای سکه و برای حالت ترکیبی هر دو جدول را نشان میدهد. این مسیر فقط خواندنی است و دادهٔ حسابداری یا موجودی ایجاد نمیکند.- چهار انتخاب مبنا و دو انتخاب بازه با
aria-pressedپیاده شدهاند. کارت نتیجه در موبایل تکستونه میشود، از tokenهای پوسته پیروی میکند و درprefers-reduced-motionگذار دکمهها حذف میشود. آزمون تخصصی درtest-balance-exposure.jsتبدیل ۷۵۰، جهت، بازه، مبنای امامی، ریز اسناد، واکنشگرایی و مستندات را کنترل میکند.
#معماری قرارداد حساب بینالمللی و اجرت چندارزی — v94
wageCurrencyKey()ارزهای قراردادی را بهtoman،dollarیاfx:<name>نگاشت میکند.wageCurrencyRate()برای ردیفهای تازه نرخ ذخیرهشده را مقدم میداند و فقط برای ردیف دلاری قدیمیِ بدون نرخ بهLIVE.dollarبرمیگردد؛ در نتیجه سازگاری دادههای قدیمی حفظ میشود.personTradeContract()تنظیماتsettleKarat،wageCurوwageRateشخص را به قرارداد سند تبدیل میکند.applyPersonTradeContract()فقطwagePresetردیف طلای بدون اجرت را آماده میکند و عمداًr.wageرا نمیسازد تا زنجیرهٔ کاتالوگ، دفتر فی وfeeRecvFor()مسدود نشود.- فرم اجرت همهٔ ارزهای کاتالوگ را عرضه میکند. نرخ ارز دستی اجباری است و نرخ دلار یا ارز دستی هنگام ذخیرهٔ اجرت گرمی/عددی در
r.wage.ratesnapshot میشود.wageRial()و در پی آن مبلغ سند و گزارش سود از همین نرخ استفاده میکنند. settleKaratهمچنان فقط در نمایش مانده و فاکتور مصرف میشود و واردrowW750Phys()یا موجودی فیزیکی نمیشود. این مرز مانع تبدیل ناخواستهٔ انبار ۷۵۰ به عیار توافقی طرف حساب است.goodsWageCurrencyData()اقلام طلاییstate.inv.goodsرا باgoodsTypes.receiveCurگروهبندی میکند و وزن، تعداد، میانگین وزنی فی و درصد و جمع اجرت فی را از پایهٔ مشترکgpBasis()میسازد؛ دفتر یا ledger موازی ایجاد نشده است.- رابطهای
.intl-contract،.doc-intl-contractو.wage-stockاز tokenهای پوسته، SVG داخلی، فوکوس صفحهکلید، dark mode، چیدمان تکستونهٔ موبایل وprefers-reduced-motionاستفاده میکنند.test-international-wage-contract.jsنگاشت ارز، fallback دادهٔ قدیمی، snapshot نرخ، قرارداد شخص، مرز موجودی و گزارش تفکیکی را کنترل میکند.
#چرخهٔ راهنمای سکه و تفکیک فیزیکی/پولی — v92
coinWorkflowForm()چهار سناریوی ویدئو را به پیشنویس متصل میکند: دریافت از کارگاه (دریافت)، فروش فیزیکی (فروش)، فروش پولی (فروشبا پرچمcoinFlow.mode=money) و تسویه با تحویل (پرداخت).- فروش پولی عمداً در مسیر فروش میماند تا قیمت طلا و سود/زیان از گزارش حذف نشود؛ یادداشت ردیف روشن میکند که سکه هنوز تحویل نشده است. تحویل واقعی از مسیر پرداخت و ردیف سکه انجام میشود.
- اجرت هر سکه از فی اصلی جداست و به ردیف مستقل ریالی تبدیل میشود. سناریوهای دریافت و پرداخت، فی فروش را غیرفعال میکنند تا کاربر بهاشتباه برای ورود یا خروج فیزیکی، ارزش فروش نسازد.
- انتخاب سناریو با دکمههای دسترسپذیر، توضیح زندهٔ قاعده، پیشنمایش تعداد و ارزش، چیدمان موبایل و
prefers-reduced-motionپیاده شده است. تست تخصصی این جریان درtest-coin-workflow.jsنگهداری میشود.
- پیشنویس راهنماییشده:
moneyCoinCurrencyForm()از داخل ثبت سند، نوع معامله، دارایی، طرف حساب، مقدار و فی را میگیرد و بهجای ورود مستقیم به جدول، یک پیشنویس قابل بازبینی میسازد. - تفکیک پولی از فیزیکی: سکه با ردیف
coinو ارز با ردیفgoodsوgMode: 'piece'ثبت میشود. روی هر دو ردیف یادداشت روشنِ «بدون جابهجایی فیزیکی» قرار میگیرد و دادهٔmoneyDealشامل نوع دارایی، نام، مقدار، فی واحد و واحد ارز را نگه میدارد. - تسویهٔ جدا: مبلغ دریافت یا پرداخت، در صورت ورود، یک ردیف مستقل
rialبا تشخیص ورود برای فروش و خروج برای خرید میسازد. انتخاب حساب بانکی روی سربرگ سند نگهداری میشود و مبلغ ریالی به مقدار ارز تبدیل نمیشود. - کنترل اشتباه رایج: متن راهنما و پیشنمایش تأکید میکنند که برای ارز باید نرخ هر واحد خود ارز وارد شود، نه مبلغ کل ریالی که به مقدار نامعقول ارز تبدیل شده باشد. پیشنویس تا زمان بررسی کاربر ذخیره نمیشود.
- رابط و آزمون: کارت معرفی، مراحل سهگانه، پیشنمایش زنده، حالت موبایل تکستونه و رنگبندی مبتنی بر tokenهای پنل اضافه شد.
test-money-coin-currency.jsسیمکشی، مدل داده، جهت تسویه، هشدار تبدیل، CSS و راهنما را کنترل میکند؛ تستهای v86 تا v90 نیز با کشv=20260829lاجرا شدند.
#ذوب لحیم با دفتر مستقل و دو عیار — v83
- در ذوب و آبشده ← دفتر ذوب، نوع ذوب را روی ذوب لحیم بگذارید تا قبض لحیم از قبض آبشدهٔ معمولی جدا و در فهرست قابل تشخیص باشد.
- برای محاسبهٔ لحیم، عیار طلای ورودی و عیار مادهٔ افزوده را جدا وارد کنید؛ سپس «عیار نهایی هدف» و «عیار مادهٔ افزوده» را در محاسبهگر بزنید. سامانه مقدار لازم را بر اساس وزن و طلای خالص ورودی پیشنهاد میکند.
- مقدار پیشنهادی تا زمانی که کاربر آن را به اقلام اضافه و قبض را ثبت نکند، اثر مالی یا تغییری در موجودی ندارد. خروجی کوره نیز با وزن و عیار واقعی ثبت میشود و افت یا سرک مستقل خودش را دارد.
- عیارهای لحیم را با آبشدهٔ عادی قاطی نکنید؛ نوع جدا باعث میشود سابقه، فیلتر و بررسی هر دو عیار برای کارگاه روشن بماند.
#گردش کارگاه، نیمساخته و دسترسی محدود — v82
- برای هر مرحلهٔ کارگاه یک نامِ جدا در امانات تعریف کنید؛ مانند چرخناورد، آبکاری، پرداخت، لیزر، فرزکاری و پالیش. این نامها حسابِ پیگیری هستند و معاملهٔ خرید یا فروش محسوب نمیشوند.
- برای ورق طلا، قطعهٔ نیمهکاره یا هر خروجیای که هنوز «کار ساخته» نیست، در کالا و انبار ← تعریف جنس نوع نیمساخته را انتخاب کنید. موجودی نیمساخته و ساخته با همین نوع کالا از هم تفکیک میشوند.
- ارسال به هر مرحله را با سندِ پرداخت و دریافتِ درستِ همان مرحله ثبت کنید؛ کسر هر مرحله از روی اختلاف وزنِ خروج و برگشت قابل مشاهده است. برای هر پارت یا مرحله، شرح روشن و حسابِ همان کارگاه را انتخاب کنید تا سابقه قابل پیگیری بماند.
- هشدارهای جهتدار و ماتریس گروههای اشخاص، نیمساخته را جدا از ساخته میسنجند. بنابراین میتوان دسترسی حسابدار کارگاه را فقط به گروه کارگاه و عملیاتهای لازم محدود کرد، بدون اینکه به دفتر ذوب، فروش یا گزارشهای دیگر دسترسی داشته باشد.
- در اتاق فرمان ← حسابدارها و دسترسیها صفحههای مجاز کاربر را جداگانه تعیین کنید و در تنظیمات ← گروههای اشخاص عملیات دریافت، پرداخت، خرید و فروش نیمساخته را کنترل کنید. دسترسیِ ندادهشده فقط هشدار ثبت میکند و تصمیم نهایی ثبت همچنان با کاربر مجاز است.
- این تفکیک باعث میشود موجودی کار ساخته هنگام گزارشگیری با نیمساخته قاطی نشود و کسری هر بخش کارگاه جداگانه قابل بررسی باشد.
#ثبت مدرن قبض ذوب و محاسبهٔ عیار هدف — v81
- در مسیر ذوب و آبشده ← دفتر ذوب، قبض ذوب با ذوبخانه/ریگیری، شماره قبض، طرف حساب و چند قلم ورودی ثبت میشود. برای هر قلم شرح، وزن، عیار و معادل ۷۵۰ نمایش داده میشود.
- بخش «محاسبهٔ عیار هدف» وزن و عیار فعلی ورودی را با عیار نهایی و عیار مادهٔ افزوده مقایسه میکند و مقدار پیشنهادی شمش، بار یا سکه را محاسبه میکند. کاربر قبل از ثبت میتواند مقدار محاسبهشده را بهعنوان یک ردیف جدید به اقلام ورودی اضافه و بازبینی کند.
- اگر عیار مادهٔ افزوده در جهت عیار هدف نباشد یا ترکیب جواب مثبت نداشته باشد، سامانه پیشنهاد ساختگی تولید نمیکند و پیام اصلاح عیارها را نشان میدهد.
- پس از برگشت از ذوب، وزن آبشده و ری واقعی ثبت میشود و معادل ۷۵۰، افت یا سرک و درصد اختلاف بهصورت زنده نمایش داده میشود. اختلاف غیرعادی بیش از ۳٪ هشدار میگیرد.
- هر پارت ذوب باید در قبض جدا ثبت شود؛ ذوب بعدی را به سند قبلی اضافه نکنید تا افت، سرک، موجودی و سود/زیان هر پارت مستقل و قابل پیگیری بماند. پس از ثبت برگشت، آبشده میتواند با همان وزن و ری به موجودی اضافه شود.
- کش و آزمون: منابع به
v=20260829bرسیدند و راهنما از منبع Markdown بازسازی شد.
- در پنل تسویهٔ ریالی کلید «انتخاب دستی شخص» فهرست همهٔ اشخاص را، مستقل از مثبت یا منفی بودن مانده، نشان میدهد. این حالت برای زمانی است که حتی برای یک بدهکار باید شماره حساب دریافت و پرداخت توافقی ثبت شود.
- در حالت دستی، فیلتر جستوجو همچنان نام، کد و تلفن را پوشش میدهد و هر کارت دکمهٔ «حساب مقصد» دارد. بانک، شماره حساب/شبا، صاحب حساب، مبلغ و یادداشت ثبت میشوند؛ اعداد حساب پیش از ذخیره با
toEnیکدست میشوند. - ثبت حساب مقصد همچنان فقط یک رکورد پیگیری در
state.rialTransfersاست و سند مالی نمیسازد. برای اشخاص طلبکار، سقف امن همان ماندهٔ خالص مثبت است؛ برای ثبت دستیِ حساب بدهکار، مبلغ توافقی باید صریحاً وارد شود و تا تأیید واریز هیچ اثر مالی ایجاد نمیکند. - حالت پیشفرض پنل تغییری نکرده است: ستون طلبکاران فقط برای تطبیق و ساخت حوالهٔ مرحلهای و ستون بدهکاران فقط برای انتخاب واریزکننده استفاده میشوند. دفتر بایگانی در هر دو حالت فقطخواندنی است.
- کش و آزمون: برچسب منابع به
v=20260829aرسید و آزمون پنل، نمایش انتخاب دستی، ثبت حساب برای بدهکار و حفظ محدودیت سقف طلبکار را کنترل میکند.
#فیشهای چندگانه و شواهد حوالهٔ مرتبط — v96
remitEvidenceشاملbank،trackingوtimeروی هر دو سند دارایremitIdذخیره میشود. ویرایش حواله همان snapshot را روی هر دو طرف بازنویسی میکند و دادههای قدیمیِ فاقد این فیلد بدون تبدیل باقی میمانند.- هر تأیید در پنل تسویه یک جفت سند مستقل و یک ورودی در
rialTransfers[].paymentsمیسازد. رکورد پرداخت،payerId،payerName، مبلغ، یادداشت و مشخصات فیش را نگه میدارد؛rialRequestPaid()همچنان فقط از جمع مبلغ همین رکوردها وضعیت تکمیل را مشتق میکند. rialPaymentListHtml()ریز چند فیش را زیر حساب مقصد نمایش میدهد، بدون اینکه برای گزارش داشبورد دفتر موازی ساخته شود. حساب مقصد تا رسیدن جمع فیشها به سقف در وضعیت ناقص میماند.rmtPrintEvidence()مشخصات بانکی را مستقل از نام طرف مقابل چاپ میکند. در نتیجهremitHidePeerفقط شرح هویتی را پنهان میکند و اطلاعات لازم برای تطبیق فیش حفظ میشود.- حوالهٔ ریالی و طلای فیزیکی از همان مدل جفت سند استفاده میکنند؛ ردیف طلایی همچنان بدون فی است. رابط شواهد و تاریخچه با RTL، پوستهٔ تیره، موبایل تکستونه و کاهش حرکت سازگار است.
#۶۷. بهروزرسانی نسخهٔ شبکه: قفل اصلی و ترتیب نصب
راهنمای تصویری و خلاصهٔ همین موضوع در صفحهٔ «بهروزرسانی کیمیا در شبکه» هم آمده است.
وقتی کیمیا روی چند سیستمِ شبکهشده نصب است، بهروزرسانی چند قانونِ ساده دارد که رعایتنکردنشان میتواند کارِ شبکه را مختل کند: همه با هم آپدیت شوند، همیشه اول نسخهٔ پشتیبان گرفته شود، و بعد از نصب، اولین اجرا با قفل اصلی باشد.
#دو نوع قفل: اصلی و کلاینت
در نسخهٔ شبکه، هر سیستم قفلِ خودش را دارد و فاصلهٔ فیزیکیِ سیستمها اهمیتی ندارد. یکی از قفلها قفل اصلی است و بقیه قفل کلاینت.
| قفل | نقش | نکته |
|---|---|---|
| قفل اصلی | مراحلِ آپدیتِ دفترها را انجام میدهد و اولین اجرای بعد از نصب باید با آن باشد. | ظاهرش شبیه بقیه است؛ یک پلاکِ شناسایی (مثلاً جاکلیدیِ زرد) به آن وصل کنید. شمارهٔ سریالش را پشتیبانی به شما گفته است. |
| قفل کلاینت | کارِ عادی روی سیستمهای دیگرِ شبکه. | تا وقتی آپدیتِ دفترها با قفل اصلی کامل نشده، سراغش نروید. |
#اینترنت و سرورِ دوردست
هر سیستم باید خودِ نسخهٔ جدید را دریافت و نصب کند؛ قفل سختافزاری حاملِ فایل آپدیت نیست. اگر پیغام The remote name could not be resolved: 'kimiadevelop.ir' نمایش داده شد، آن سیستم به سرور بهروزرسانی دسترسی ندارد. اتصال اینترنت و دسترسی به دامنهٔ kimiadevelop.ir را روی همان سیستم بررسی کنید.
اگر سرور در دفتر دیگری است یا شرکتِ خدمات ابری آن را نگهداری میکند، پیش از شروع با مسئول سرور هماهنگ کنید. نسخهٔ کیمیا روی سرور و همهٔ کلاینتهای در حال استفاده باید یکسان شود؛ یک کلاینت را جداگانه آپدیت نکنید و با نسخهٔ متفاوت به دفتر مشترک وارد نشوید.
قفل فقط مجوز اجرای کیمیاست؛ جایگزین اینترنت یا فایل نصبِ نسخهٔ جدید نیست.
#کیمیا خودش خبر میدهد
اگر به اینترنت متصل باشید و نسخهٔ جدیدی منتشر شده باشد، کیمیا در گوشهٔ سمت چپِ صفحه آن را دانلود میکند و با پایانِ دانلود، نشانهٔ همان گوشه تغییر میکند. هنگامِ بستنِ برنامه در آخرِ وقت، پیامِ بهروزرسانی ظاهر میشود که شاملِ:
- لینکِ «در این بروزرسانی چی داریم؟» برای دیدنِ فهرستِ تغییرات؛
- تاریخِ انتشارِ نسخهٔ جدید؛
- و سه گزینه: نه، تهیهٔ نسخهٔ پشتیبان و خروج، و بکاپ و بروزرسانی نرمافزار.
#یا همه، یا هیچکس
نسخهٔ کیمیا روی همهٔ سیستمهای شبکه باید یکی باشد. اگر فعلاً نمیخواهید آپدیت کنید، به بقیهٔ کاربرانِ شبکه هم بگویید آپدیت نکنند و همگی موقعِ خروج از «تهیهٔ نسخهٔ پشتیبان و خروج» استفاده کنید؛ هر وقت همه آماده بودند، با هم بهروز کنید.
بهروزرسانیِ نامتوازن (یک سیستم جدید، بقیه قدیمی) میتواند شبکه را به مشکل بیندازد. «همه با هم» قانونِ طلایی است.
#اول پشتیبان، بعد نصب
روی هر سیستم گزینهٔ «بکاپ و بروزرسانی نرمافزار» را بزنید. کیمیا اول یک نسخهٔ پشتیبان میگیرد و در بالای صفحه تأیید میکند که بکاپ درست ذخیره شد، بعد نصب را شروع میکند. همین کار را روی همهٔ سیستمهای شبکه تکرار کنید.
در حینِ نصب دست نگه دارید: سیستم را خاموش نکنید، کیمیا را دوباره اجرا نکنید و مراقب باشید برق قطع نشود تا نصب نصفه نماند. نوارِ سبزِ پیشرفت یعنی کار در جریان است؛ تا پایان صبر کنید.
#مهمترین نکته: اولین اجرا با قفل اصلی
بعد از نصبِ آپدیت، برای بارِ اول باید کیمیا را با قفل اصلی اجرا کنید. مهم نیست قفل اصلی به کدام سیستم وصل باشد؛ روی هر سیستمی که هست، کیمیا را اول همانجا باز کنید. کیمیا سریالِ قفل اصلی را نشان میدهد تا مطمئن شوید همان قفل است.
#چرا ترتیبِ قفلها مهم است؟
اولین ورود به دفتر بعد از نصب ممکن است ساختار پایگاه داده را برای نسخهٔ جدید ارتقا دهد؛ برای نمونه، فیلدهای جدید ساخته میشوند. این عملیات باید یکبار و با قفل اصلی انجام شود. اگر قفل کلاینت پیش از پایان این مرحله وارد همان دفتر شود، ممکن است دو فرایندِ ارتقا با هم درگیر شوند و فیلدهای تکراری، خطای فنی یا خرابی دفتر ایجاد کنند.
ترتیبِ ایمن همیشه این است:
- نسخهٔ جدید را روی همهٔ سیستمها نصب کنید.
- کیمیا را ابتدا با قفل اصلی اجرا کنید.
- همهٔ دفترهای جاری را یکبار با قفل اصلی باز کنید تا ارتقا کامل شود.
- فقط بعد از آن، کار با قفلهای کلاینت را شروع کنید.
اگر اشتباهی ابتدا با قفل کلاینت اجرا کردید، ادامه ندهید و برنامه را چند بار باز نکنید؛ با پشتیبانی کیمیا هماهنگ کنید تا وضعیت دفتر بررسی شود.
#هر دفترِ فعال را یک دور باز کنید
با قفل اصلی وارد هر دفتری که واقعاً با آن کار میکنید بشوید — همین یک دور کافی است تا مراحلِ آپدیت روی آن دفتر انجام شود. اگر دو دفترِ کاری دارید، هر دو را یکبار باز کنید.
دفترهایی که دیگر با آنها کار نمیکنید — مثلاً دفترهای آرشیو یا سالهای مالیِ قبل — نیازی به باز شدن با قفل اصلی ندارند. فقط دفترهای جاری مهماند.
وقتی آپدیتِ دفترها با قفل اصلی کامل شد، سراغِ سیستمهای دیگر با قفلِ کلاینت بروید و کارِ عادی را بدونِ مشکل شروع کنید.
#ربط این بخش به بقیهٔ راهنما
#۶۸. کسر و اضافه: اصلاح حساب بدون جابهجایی فیزیکی
راهنمای گامبهگام و تصاویرِ همین موضوع در صفحهٔ «کسر و اضافه در کیمیا» آمده است.
قاعدهٔ اصلی ساده است: هرجا چیزی فیزیکی ردوبدل نشده و موجودیِ واقعیِ پول، طلا، چک یا جنس نباید تغییر کند، اما لازم است ماندهٔ یک حساب اصلاح، تعدیل، کم یا زیاد شود، از کسر و اضافه (کد ۸) استفاده کنید.
#پیش از ثبت، این دو پرسش را جواب دهید
- آیا پول، طلا، چک یا جنس واقعاً وارد یا خارج شده است؟ اگر بله، همان نوعِ واقعیِ دریافت یا پرداخت را ثبت کنید.
- آیا فقط ماندهٔ طرفحساب باید تغییر کند؟ اگر بله، کسر و اضافه انتخاب درست است.
در نسخهٔ دسکتاپِ نمایشدادهشده در آموزش، قاعدهٔ جهت چنین است:
| جهت ردیف | اثر حسابداری |
|---|---|
| دریافت + کد ۸ | بدون دریافت فیزیکی، بدهیِ طرف کم میشود و برای شما زیان محسوب میشود. |
| پرداخت + کد ۸ | بدون پرداخت فیزیکی، طلبِ طرف شکل میگیرد یا بیشتر میشود و برای شما سود محسوب میشود. |
در پنل وب، همین مفهوم با جهتِ صریحِ «تخفیف دادم» و «تخفیف گرفتم» نشان داده میشود؛ جزئیاتِ رفتار پنل در بخش کسر و اضافه آمده است.
#مثال ۱: اختلاف حساب طلایی
فرض کنید پس از بررسی پرینتها، اختلاف حساب ۱٫۸۸۰ گرم است و توافق میکنید هر طرف نیمی از آن، یعنی ۰٫۹۴۰ گرم، را بپذیرد. برای کمکردن سهم پذیرفتهشده از بدهی طرف، ردیف دریافت با کد ۸ ثبت میشود؛ نه آبشدهای گرفتهاید، نه متفرقه و نه کارِ ساختهای وارد موجودی شده است.
- بابت را «اصلاح حساب» بگذارید.
- در یادداشت بنویسید: «اختلاف ۱٫۸۸۰ گرم بود؛ نصفنصف پذیرفتیم.»
- به فاکتور یا پرینتِ مبنای توافق اشاره کنید تا علتِ عدد بعداً روشن بماند.
#مثال ۲: هزینهٔ بانکی
اگر بانک در پرینت حساب ۱۵٬۰۰۰ تومان بابت صدور دستهچک کم کرده، پولی را دستی به بانک ندادهاید. کد ۸ را با بابت «هزینهٔ بانکی» و یادداشت «هزینهٔ صدور دستهچک» ثبت کنید. پس از ثبت، موجودی حساب بانکی باید به همان اندازه کم شود و هزینه در خلاصه وضعیت بهعنوان زیان دیده شود.
#مثال ۳: اجرت تعمیرات
مشتری گوشوارهای برای تعمیر داده و باید ۳۰٬۰۰۰ تومان اجرت بپردازد، اما هنوز پول را نگرفتهاید. ابتدا با کد ۸ و بابت «اجرت تعمیرات» مشتری را بدهکار کنید. وقتی پول واقعاً دریافت شد، آنوقت یک دریافت نقدی یا بانکیِ جداگانه ثبت کنید.
#مثال ۴: اجرت حمل
اگر حملکننده بابت انتقال طلا از شهرستان طلبکار شده ولی هنوز پولی به او ندادهاید، با کد ۸ و بابت «اجرت حمل» طلبش را ثبت کنید. پرداخت نقدی یا حوالهٔ بانکی فقط زمانی ثبت میشود که وجه واقعاً جابهجا شود.
#مثال ۵: تفاوت شمش
اگر از آبشدهفروش شمش گرفتهاید و او بابت تفاوت شمش مبلغی مطالبه کرده که هنوز نپرداختهاید، کد ۸ را با بابت «تفاوت شمش» بزنید تا طلب او در حساب بنشیند. این ردیف نباید موجودی شمش را دوباره تغییر دهد؛ پرداختِ واقعی بعداً با سند مناسب خودش ثبت میشود.
#بابت و یادداشت را جدی بگیرید
اگر عنوانِ موردنظر در فهرست بابتها نیست، یکبار آن را تایپ و اضافه کنید. یادداشت باید بگوید عدد از کجا آمده و توافق چه بوده است. بهترین حالت این است که خودِ سند، ماهها بعد هم بدون تکیه بر حافظه توضیح بدهد چرا این اصلاح ثبت شده است.
خلاصه: کد ۸ برای جابهجایی فیزیکی نیست؛ برای تغییرِ مانده است. هر ردیفِ کسر و اضافه نیز باید در سود یا زیان شما اثر متناظر داشته باشد.
#۶۹. اولین مرجوعی یک جنس: ثبت مبنای فی بدون تغییر موجودی
راهنمای مرحلهبهمرحله و تصاویر این قابلیت در صفحهٔ «فی دریافتیِ اولین مرجوعی» آمده است.
گاهی پس از پایان راهاندازی اولیه، اولین گردشِ یک جنس در کیمیا مرجوعی است؛ یا مشتری قدیمی جنسی را برمیگرداند که خرید اصلی آن پیش از شروع کار با برنامه ثبت شده است. در این حالت، فیِ روی مرجوعی فقط شرایط برگشت را نشان میدهد و به برنامه نمیگوید آن جنس قبلاً با چه فیای برای شما تمام شده بود.
اگر جنس نه موجودی افتتاحیه داشته باشد و نه ورودیِ غیرمرجوعی، پس از تکمیل ردیفِ مرجوعی پنجرهٔ «فی دریافتی نامشخص است» باز میشود. این هشدار هم در بنکداری برای «دریافت مرجوعی» و هم در تکفروشی برای «خرید مرجوعی» عمل میکند.
#چه عددی وارد شود؟
- اگر اجرت جنس درصدی بوده، درصد اجرت را انتخاب و میانگینِ فی دریافتی قبلی را وارد کنید.
- اگر مبنا مبلغ هر گرم بوده، مبلغ هر گرم را انتخاب کنید.
- عددِ ورودی باید «پای خودت» باشد؛ یعنی فیای که جنس قبلاً برای شما تمام شده، نه فیِ مرجوعی مشتری.
#سند داخلی چه کاری میکند؟
پس از تأیید، یک سند سیستمی در «حساب داخلی — بررسی و اصلاح موجودی» ساخته میشود. ردیف این سند وزن صفر دارد و فقط مبنای تاریخی فی را نگه میدارد؛ بنابراین:
- وزن و موجودی فیزیکی تغییر نمیکند.
- ماندهٔ طرفحساب تغییر نمیکند.
- گزارش کارکرد اجناس و سود و زیان بهجای حدسِ صفر، مبنای ثبتشده را استفاده میکنند.
- اگر بعداً ورودی واقعی برای همان جنس ثبت شود، میانگین واقعیِ ورودیها بر این مبنای کمکی مقدم است.
#مثال عددی
۴۵٫۲۰۰ گرم جنس با اجرت ۱۵٪ مرجوع شده و فی دریافتی قبلی شما ۱۰٪ بوده است. اختلاف قابل محاسبه چنین است:
۴۵٫۲۰۰ × (۱۵٪ − ۱۰٪) = ۲٫۲۶۰ گرم
بدون ثبت مبنای ۱۰٪، برنامه مجبور بود سود و زیان را نسبت به صفر بسنجد و گزارش عدد نادرستی میداد.
قاعده: مبنای فی فقط وقتی پرسیده میشود که هیچ سابقهٔ قابل اتکایی وجود ندارد؛ این سند برای اصلاح گزارش است، نه ساختن موجودی.
#۷۰. اتصال کیمیا به سامانه مؤدیان: شناسه یکتا و توکن اقتصادی
راهنمای تصویری مرحلهبهمرحله و تصاویر این فرایند در صفحهٔ «اتصال کیمیا به سامانه مؤدیان» آمده است.
اتصال کیمیا به سامانه مؤدیان به معنی ارسال خودکار همهٔ اطلاعات نیست. ابتدا در پروندهٔ مالیاتی شناسهٔ یکتا بگیرید، سپس در پنل شرکت معتمد دادپردازی معتمد تیس ثبتنام و توکن اقتصادی را دریافت کنید. ارسال صورتحساب باید فقط برای اسنادی انجام شود که کاربر انتخاب کرده است.
مسیر انجام کار
- ورود به پروندهٔ مالیاتی با رمز یکبارمصرف و انتخاب «ورود به پرونده».
- بازکردن بخش شناسهٔ یکتای حافظهٔ مالیاتی و انتخاب شرکت معتمد سامانههای دولتی؛ نام شرکت را با «دادپردازی معتمد تیس» تطبیق دهید.
- کپیکردن شناسهٔ یکتا و تکمیل ثبتنام حقیقی در پنل شرکت معتمد.
- واردکردن شناسهٔ یکتا در بخش ویرایش کد حافظهٔ مالیاتی، خروج و ورود دوباره برای فعالشدن پنل.
- بازکردن «راههای ارسال صورتحساب»، ساخت توکن جدید و نگهداری امن توکن اقتصادی.
نکتهٔ امنیتی: شناسهٔ یکتا و توکن اقتصادی دو مقدار متفاوتاند. توکن را در متن عمومی، پیامرسان یا کد سمت کاربر قرار ندهید. اتصال آماده است، اما ارسال هر صورتحساب همچنان باید با انتخاب و کنترل کاربر انجام شود.
#۷۱. ارسال گروهی صورتحساب با فایل اکسل: انتخاب، آپلود و پیگیری
راهنمای تصویری این فرایند و تصاویر مراحل در صفحهٔ «ارسال فایل صورتحساب به سامانه مؤدیان» آمده است.
برای ارسال گروهی، ابتدا اسناد را در کیمیا بررسی کنید، فایل اکسل استاندارد را بگیرید و همان فایل را در پنل شرکت معتمد تیس بارگذاری کنید. فایل اکسل خروجی را باز یا ویرایش نکنید؛ ساختار و قواعد آن برای پذیرش سامانه آماده شده است.
مسیر انجام کار
- از ابزارها و سامانه مؤدیان، بازهٔ تاریخ را انتخاب کنید و اسناد غیرلازم را نشاندار کنید؛ برای چند ردیف Ctrl و Space هم قابل استفاده است.
- تبدیل به اکسل را بزنید و فایل را ذخیره کنید؛ فایل را باز و دوباره ذخیره نکنید.
- در پنل تیس، صورتحسابهای الکترونیکی و آپلود فایل را باز کنید.
- بدون اطلاعات خریدار و الگوی طلا، جواهر و پلاتین را انتخاب کنید، سپس فایل را بارگذاری کنید.
- پیام موفقیت و وضعیت ارسالشده را بررسی کنید؛ در کیمیا Refresh بزنید تا وضعیت پردازش را ببینید.
اگر تا ۷۲ ساعت تأیید نشد یا وضعیت قرمز و ناموفق شد، جزئیات خطا را بخوانید، علت را در کیمیا اصلاح کنید، خروجی تازه بگیرید و دوباره ارسال کنید. خطاهای محتوایی و قواعد پذیرش معمولاً مربوط به سامانه مؤدیان است، نه مسیر انتقال تیس. پس از پایان کار، اسناد ارسالشده را در کیمیا نشاندار کنید تا دوباره انتخاب نشوند.