در سالهای ۲۰۲۰ و ۲۰۲۱ بهصورت فریلنس و در نقش توسعهدهندهٔ فولاستک برای صرافی بانک رفاه کار کردم. حسابداری حوالههای ارزی این صرافی در یک صفحهگسترده انجام میشد. سامانهای را ساختم که جای آن را گرفت: حوالهها، کارمزدها، ارز تخصیصی بانک مرکزی و نیما و ماندهٔ حساب با هر طرف حساب در یک پایگاهدادهٔ SQL Server ثبت و در یک جا محاسبه میشد.
زمینه
صرافی از طرف مشتریهایش ارز میفرستد و دریافت میکند. در یک حواله ممکن است چند طرف درگیر باشند: مشتری، صرافیها و کارگزارهای دیگری که کارمزد یا کسوراتی برمیدارند و در مورد ارز تخصیصی، بانک مرکزی و سامانهٔ نیما. در پایان، هر طرف به ارزی مشخص مبلغی بدهکار یا بستانکار است.
پیش از این پروژه، این کار در صفحهگستردهای انجام میشد که هر حواله یک ردیف آن بود. ستونهای فرمولدار مبلغ تبدیل، مبلغ نهایی حواله، کسورات هر صرافی و کارگزار و عددهایی را میساختند که ماندهٔ هر طرف حساب از آنها به دست میآمد.
مسئلهٔ مهندسی
صفحهگسترده برای کار یک نفر ابزار خوبی است، اما برای سابقهٔ مالی مشترک ابزار ضعیفی است. بهطور کلی، انتقال این کار به یک سامانه یعنی از پس چهار چیز برآمدن:
- فرمولها همان قواعد کسبوکار بودند. هر مبلغ از یک ستون صفحهگسترده میآمد. سامانه باید همان عددها را تولید میکرد؛ وگرنه کسی نمیتوانست آن را با چیزی که از قبل میشناخت مقایسه کند.
- کارمزدها یکسان نیستند. انواع مختلف حواله و جفتارزهای مختلف کارمزدهای متفاوتی دارند که سمت صرافی یا سمت کارگزار گرفته میشوند و بهازای هر هزار واحد، بهازای هر واحد ارز یا بهصورت ضریب اعمال میشوند.
- ماندهها دادهٔ مشتقاند. اینکه هر طرف حساب چقدر بدهکار یا بستانکار است، از حوالهها به دست میآید. اگر حوالهای تغییر کند و ردیفهای ماندهاش تغییر نکنند، گزارشها بیآنکه خطایی دیده شود غلط میشوند.
- سابقه از قبل وجود داشت. حوالههای گذشته در صفحهگسترده بودند و باید با همان محاسبهها منتقل میشدند، نه اینکه دوباره تایپ شوند.
کاری که انجام دادم
سامانه را به شکل یک برنامهٔ ASP.NET Core MVC روی SQL Server ساختم. کار روی .NET Core 3.1 شروع شد و در دسامبر ۲۰۲۰ آن را به .NET 5 منتقل کردم. بخشهای اصلی آن:
- ثبت حواله. هر حواله ارز مبدأ و مقصد، بانک و کشور، نرخ، معادل ریالی، مشتری، حساب و طرف حساب را نگه میدارد و پیوستها و تاریخهای مراحلش هم با آن ثبت میشوند؛ تاریخها به تقویم شمسی وارد و نمایش داده میشوند.
- انواع حواله در یک درخت قابل تنظیم. انتقال ارز، ارز تخصیصی بانک مرکزی، خرید و عودت نیما و مدیریت وجوه دستههایی در یک درختاند و ماهیت هرکدام واریز، برداشت یا کارمزد تعیین شده است. هر نوع، کارمزدها و مراحل پیشفرضی دارد که فرم حوالهٔ جدید از پیش با آنها پر میشود.
- یک سرویس محاسبه. این سرویس در سمت سرور مبلغ تبدیل، مبلغ نهایی حواله، کسورات صرافیها و کارگزارها و ردیفهای بدهکار و بستانکار هر طرف حساب را محاسبه میکند. این محاسبهها همان ستونهای صفحهگستردهای را بازتولید میکنند که جایشان را گرفتهاند.
- ابزار درونریزی CSV برای صفحهگستردهٔ قدیمی. خروجی قدیمی را میخواند، مشتریها، گروههای مشتری و انواع حوالهای را که هنوز وجود ندارند میسازد و هر حوالهٔ گذشته را پیش از ذخیره از همان سرویس محاسبه عبور میدهد.
- گزارشها. ماندهٔ هر مشتری، هر کارگزار و هر جفت کارگزار و مشتری، برای هر ارز، به تفکیک بدهکار و بستانکار و همراه با کارمزد صرافی و کارگزار؛ بهعلاوهٔ یک صورتحساب تفصیلی. جدولها در سمت سرور صفحهبندی و جستوجو میشوند و خروجی CSV دارند.
- پنل مدیریت با کنترل دسترسی. کاربران نقش دارند و عضو گروههای کاربریاند. وقتی تاریخ اتمام یک حواله ثبت شود، فقط مدیر میتواند آن را ویرایش کند.
نکتههای طراحی
این نکتهها استدلال پشت طراحی را توضیح میدهند. موضوعشان خود این برنامه است، نه سامانههای دیگر بانک.
صفحهگسترده بهعنوان مشخصات
هر عدد در سرویس محاسبه با ستونی از صفحهگسترده که جایش را گرفته مستند شده است و مقدارهای محاسبهشده همراه حواله ذخیره میشوند. به این ترتیب میشد هر عدد سامانه را با صفحهگستردهٔ اصلی مقایسه کرد و قواعد هم بهجای پخش شدن در صفحههای مختلف، در یک سرویس میماندند.
ماندهها حاصل جمعاند، نه مقدار ذخیرهشده
هیچ مشتری یا طرف حسابی ماندهای ذخیرهشده ندارد که به مرور بهروز شود. هر حواله ردیفهای بدهکار و بستانکار خودش را دارد و گزارشها آنها را جمع میزنند. پس مانده نمیتواند با حوالههایی که پشت آن هستند تناقض داشته باشد و اصلاح یک حواله، هر گزارشی را که آن حواله را در بر دارد هم اصلاح میکند.
حواله و عددهایش با هم ذخیره میشوند
حوالهٔ جدید همراه با کارمزدها، مراحل، عددهای محاسبهشده و ردیفهای ماندهاش به شکل یک گراف شیء ساخته میشود و با یک بار ذخیرهسازی در EF Core نوشته میشود. ویرایش، عددها را درجا وصله نمیکند: رکورد قدیمی را حذف میکند و یک نسخهٔ دوبارهمحاسبهشده را در همان ذخیرهسازی درج میکند. EF Core هر بار ذخیرهسازی را در یک تراکنش پایگاهداده اجرا میکند؛ بنابراین عددهای ذخیرهشده همیشه از نسخهٔ فعلی حواله میآیند.
قواعد کارمزد به شکل داده
کارمزدهای پیشفرض ردیفهای دادهاند، نه کد. هرکدام به یک نوع حواله و یک جفتارز تعلق دارد، یک مقدار برای صرافی و یک مقدار برای کارگزار دارد و مشخص میکند چطور اعمال شود: بهازای هر هزار واحد، بهازای هر واحد ارز یا بهصورت ضریب. حوالههای جدید از همین پیشفرضها شروع میشوند و در هر مورد میشود آنها را تغییر داد.
فناوریها
- ASP.NET Core MVC: .NET Core 3.1 و سپس .NET 5 از دسامبر ۲۰۲۰
- EF Core و SQL Server
- ASP.NET Core Identity
- Autofac و AutoMapper
- Serilog، با ثبت خطاها در یک جدول SQL Server
- CsvHelper
- jQuery و DataTables، با صفحهبندی سمت سرور
نتیجه
- حسابداری حوالهها از صفحهگسترده به یک پایگاهدادهٔ SQL Server منتقل شد، با یک سرویس محاسبه که ثبت، ویرایش و درونریزی سوابق گذشته همه از آن استفاده میکنند.
- گزارشهای مانده به تفکیک مشتری، کارگزار و ارز که از همان ردیفهای هر حواله ساخته میشوند و خروجی CSV دارند.
مطالب مرتبط
نرمافزار مالی دیگری که در این سایت معرفی شده، داشبورد شاخصهای مالی است. برای کارهای بکاند در سامانههای مالی یا سامانههای داخلی کسبوکار، صفحهٔ همکاری را ببینید.
پرسشهای رایج
مهدی مولوی برای صرافی بانک رفاه چه چیزی ساخت؟
او در سالهای ۲۰۲۰ و ۲۰۲۱ بهصورت فریلنس و در نقش توسعهدهندهٔ فولاستک، برای صرافی بانک رفاه سامانهای ساخت که جایگزین صفحهگستردهٔ حسابداری حوالههای ارزی این صرافی شد.
این سامانه چه چیزهایی را ثبت میکند؟
حوالهها را با ارز مبدأ و مقصد، بانک، کشور، نرخ و معادل ریالی؛ کارمزدها و کسورات صرافیها و کارگزارها؛ ارز تخصیصی بانک مرکزی و خرید و عودت نیما؛ و ماندهٔ بدهکار و بستانکار هر طرف حساب.
دادههایی که از قبل در صفحهگسترده بود چه شد؟
یک ابزار درونریزی CSV خروجی صفحهگستردهٔ قدیمی را میخواند، مشتریها و انواع حوالهای را که هنوز وجود نداشتند میساخت و هر حوالهٔ قدیمی را پیش از ذخیره از همان سرویس محاسبهای عبور میداد که حوالههای جدید از آن میگذرند.
در این پروژه از چه فناوریهایی استفاده شد؟
ASP.NET Core MVC که روی .NET Core 3.1 شروع شد و در دسامبر ۲۰۲۰ به .NET 5 رسید، همراه با EF Core و SQL Server، ASP.NET Core Identity، Autofac، AutoMapper، Serilog و CsvHelper.
در همین بخش
- پلتفرم آزمون تطبیقی: سنجش مبتنی بر IRT برای حدود ۸۹ هزار دانشآموز
- پردازش سؤال با هوش مصنوعی: از PDF آزمون تا سؤالهای ساختیافته در LaTeX
- «همسایه»: سامانهٔ ابری مدیریت ساختمان و مجتمع مسکونی
- پلتفرم تحویل و خدمات در محل: سفارش، پیک، تکنسین و انبار در یک سامانه
- دسترسپذیری بالا در اوج آزمونها: Redis Sentinel برای ۴۵ تا ۷۰ هزار کاربر همزمان
- داشبورد شاخصهای مالی برای MBRI
- پلتفرم میکروسرویسی چندمستأجری: زیرساخت مستأجر، پیامرسانی و گردشکار (در حال توسعه)
مهدی مولوی