تا قبل از این، وب سرویس API سیستم مالی نوسا تحت استاندارد SOAP ارائه می شد. به این ترتیب مراکز می توانستند از طریق یک کلاینت Soap به تعداد مشخصی از متدهای API که از قبل تعریف شده اند، دسترسی داشته باشند. و اما از این پس و با توجه به توسعه استاندارد REST در سیستمهای نوسا، خدمات API سیستم مالی، دیگر منحصر به متدهای از قبل تعریف شده نیست و مراکز می توانند متدهای قابل تعریف (User Defined) را نیز طبق سلیقه و نیازهای خود تعریف کنند و از این طریق خدمات API خود را شخصی سازی (Customise) کرده و توسعه دهند.
ارائه خدمات API سیستم مالی تحت REST
توضیح: برای درک این مطلب لازم است که با مفاهیم، ساختار و نحوه عملکرد CPUConnector آشنا باشید لذا اگر تسلط کافی دراین موضوع ندارید بهتر است قبلا مطلب راه اندازی AccCPUConnector: یک سرویس REST برای تعامل راه دور با سیستم مالی را مطالعه بفرمایید.
ارائه خدمات تحت REST اساسا از طریق یک ماژول CPUConnector انجام می شود. یادآوری می شود که این ماژول حاوی یک فایل به نام Script.js است که توابع مورد نظر برای خواندن (و نوشتن) داده ها در پایگاه مبدا در این فایل ایجاد می شود و سپس از طریق یک کلاینت REST ، این توابع به همراه پارامترهای آنها Call می شود. در این مطلب، توابع ذکر شده در واقع همان متدهای API سیستم مالی می باشد. این متدها به دو بخش تقسیم می شود: متدهای از پیش تعریف شده و متدهای قابل تعریف
1-متدهای از پیش تعریف شده (AccUtils)
این متدها شامل خدمات عام و پرکاربرد سیستم مالی است که از قبل در سیستم تعریف شده است و در هر بار بروزرسانی سیستم مالی این متدها نیز بطور خودکار بروزرسانی می شود. این متدها از طریق موجودی بنام AccUtils و با ساختار زیر ارائه می شود:
AccUtils = {
ویژگی ها (Properties)
UseHTTPS Boolean/RW
HostURL String/RW
UserName String/RW
Password String/RW
RunInServer Boolean/RW
متدها
تعریف اطلاعات تلفن و نشانی، تفصیلی و مرکز مصرف یا تامین کالا و خدمات
|
WS_AddDet
|
افزودن سند حسابداری
|
WS_AddArt
|
افزودن برگه درخواست کالا
|
WS_AddInvPreArt
|
افزودن برگه انبار
|
WS_AddInvArt
|
افزودن برگه درخواست خدمات
|
WS_AddSrvPreArt
|
افزودن برگه انجام خدمات
|
WS_AddSrvArt
|
افزودن برگه فروش
|
WS_AddSalesArt
|
اصلاح طرف حسابهای یک برگه فروش
|
WS_ModifySalesArtOpps
|
حذف یک برگه درخواست کالا
|
WS_DelInvPreArt
|
حذف سطرهایی از یک برگه درخواست کالا
|
WS_DelInvPreTrans
|
لغو سطرهایی از یک برگه درخواست کالا
|
WS_CancelInvPreTrans
|
حذف یک برگه درخواست خدمات
|
WS_DelSrvPreArt
|
حذف سطرهایی از یک برگه درخواست خدمات
|
WS_DelSrvPreTrans
|
لغو سطرهایی از یک برگه درخواست خدمات
|
WS_CancelSrvPreTrans
|
اخذ مشخصات کالاها و خدمات
|
WS_GetMatList
|
اخذ مشخصات تعرفهها
|
WS_GetTariffList
|
اخذ موجودی کالاها، انبارها، بچها و رخدادهای مرجع کالاهای شناسایی ویژه + اخد مقادیر درخواست و رزرو کالاها
|
WS_GetMatRemain
|
ساختار متدهای این موجود، به شکل زیر است:
function MethodName(dbName, data): String
ملاحظه می کنید که این متدها دارای دو پارامتر هستند که اولی نام پایگاه مالی (dbName) است و پارامتر دوم یک متن xml است که بسته به هر متد، داده های لازم را در قالب attribute ها به تابع پاس می کند.
مثال: افزودن یک تامین کننده جدید (با کد تفصیلی)
برای افزودن یک تامین کننده جدید ابتدا یک تابع به صورت زیر در فایل Script.js ایجاد می کنیم:
function AddInvCenter(p) {
var DBName = "_AccXP_hamayesh992";
AccUtils.HostURL = "192.168.100.25";
AccUtils.UserName = "NOSA-Test\\NosaXPServer";
AccUtils.Password = "Nosa1234";
return AccUtils.WS_AddDet(DBName, p)
}
همانطور که می دانید برای افزودن یک رکورد در دفتر تلفن و نشانی، یک مرکز تامین و مصرف و یک تفصیلی جدید، از متد WS_AddDet استفاده می کنیم. چند سطر اول این تابع ویژگی های نام پایگاه، نشانی URL پایگاه و نام و کلمه عبور کاربر را تعیین می کند و در سطر آخر، نکته قابل توجه پارامتر p است که در واقع متن xml حاوی داده های مرتبط با کد تفصیلی و مرکز تامین و مصرف مورد نظر است. این پارامتر از کلاینت REST پایگاه فرایندها به این تابع پاس می شود. برای این کار باید در گردش کار مورد نظر (مثلا تامین کالاها) ، یک تابع به شکل زیر ایجاد شود:
function WorkActionAddInvCenter() {
var data='';
data+="<_DetL ParentCode='02/0012' Num='14' Name='ديجي كالا' />";
data+='<_ICL ParentCode="05" Num="5" Name="فروشگاه آنلاين ديجي كالا" IsSuppiler="1" />';
data+='';
var res=RemoteCallAPI('http://nosa-test/AccCPUConnector/', 'AddInvCenter', data, 'CPUConnUser', 'Nosa1234' ) ;
return res;
}
در این تابع، متن xml داده های مورد نظر برای تامین کننده را برای درج در درخت مراکز تامین و مصرف و درخت تفصیلی ها تعریف می شود و در متغیر data قرار می گیرد و سپس در مرحله آخر از طریق تابع RemoteCallAPI این متغیر به عنوان پارامتر به تابع AddInvCenter در سرور مالی راه دور پاس می شود.
یادآوری: تابع RemoteCallAPI حاوی یک کلاینت REST است که از آن طریق، پارامتر یاد شده را به ماژول CPUConnector می فرستد و در آنجا به تابع AddInvCenter در script.js پاس می کند.
تابع RemoteCallAPI در برنامه گردش کار و به شکل زیر است:
function MakeBasicAuthorization(userName, password) {
var str = userName + ':' + password;
var arr = [];
for (var i=0; i
arr.push(str.charCodeAt(i));
return "Basic " + WorkUtils.BtoA(arr);
}
function RemoteCallAPI (url, funcName, funcParam, userName, password) {
var restClt = WorkConnUtils.CreateRestClient(url + 'AccCPUConnector.dll/datasnap/rest/TAccCPUConnectorMethods/AccCPUCallFunction' ) ;
restClt.Method = RestEnums.RequestMethod.POST;
restClt.AddHTTPHeader('Authorization', MakeBasicAuthorization(userName, password));
var cnt = {};
cnt.FuncName = funcName;
cnt.FuncParam = funcParam;
restClt.AddBody(JSON.stringify(cnt));
restClt.Execute();
var res = "";
try {
var res = JSON.parse(restClt.Response.Content);
}
catch(e) {
}
if (res) {
if (res.error)
throw res.error;
return res.result[0];
} else {
throw 'StatusCode: ' + restClt.Response.StatusCode +
'\nStatusText: ' + restClt.Response.StatusText +
'\nResponseContent: ' + restClt.Response.Content;
}
2-متدهای قابل تعریف (از طریق (WorkADOSelect
در تعریف متدهای از پیش تعریف شده، سعی شده است عملیات استاندارد و کاربردی پوشش داده شود اما واضح است که عملیات حسابداری منحصر به این متدها نیست و لذا عملیات دیگری نیز وجود دارد که ممکن است مراکز بخواهند از طریق سرویس API به مشتریان ارائه کنند. به همین دلیل متدهای API مرتبط با این عملیات باید به شکل اختصاصی برای هر پایگاه سیستم مالی تعریف شود. برای مثال حسابهای مرتبط با بدهی مشتریان اختصاصی هر مرکز می باشد.
مثال: خواندن مانده بدهی مشتری
حال فرض کنید می خواهیم یک متد API برای خواندن مانده بدهی یک مشتری تعریف کنیم. در این صورت ابتدا تابع مانده یک تفصیلی را در Script.js ایجاد کنیم:
تابع مانده یک تفصیلی
function UD_GetDetBalance(p) {
var codes=JSON.parse(p);
WorkADOSelect.DBName = "_AccXP_hamayesh992";
WorkADOSelect.SelectClause = "Det_Code=_Dets.det_Code," +
"Det_Balance=SUM(_Transes.tr_Deb)-SUM(_Transes.tr_Cre)";
WorkADOSelect.FromClause = "_Transes " +
"inner join _Accs on _Transes.tr_AccKey=_Accs.acc_Key " +
"left join _Dets on _Transes.tr_Det1Key=_Dets.det_Key ";
WorkADOSelect.WhereClause = "_Dets.Det_Code = '" + codes.detCode + "'" +
" and _Accs.acc_Code = '" + codes.accCode + "'" ;
WorkADOSelect.GroupByClause= "_Dets.det_Code";
var res2=WorkADOSelect.Execute();
return JSON.stringify(res2);
}
در این تابع مانده یک تفصیلی خاص (det_Code) وابسته به یک حساب خاص (acc_Code) بازگشت داده می شود.
توضیح: البته مانده بدهی یک مشتری بصورت واقعی به این سادگی نیست و معمولا از چند حساب و با شرایط پیچیده تری استخراج می شود لذا برای ساده کردن مساله در این مثال فقط یک کد حساب را در نظر گرفته ایم.
حال باید در برنامه گردش کار تابعی بنویسیم که کد تفصیلی و کد حساب مورد نظر کاربر را به صورت پارامتر به تابع بالا پاس کند:
تابع گردش کار مانده بدهی یک مشتری
function GetCustomerDebt(Det_Code, Acc_Code) {
var custCodes={};
custCodes.detCode=Det_Code;
custCodes.accCode=Acc_Code;
var jCustCodes=JSON.stringify(custCodes);
var res= RemoteCallAPI ('http://nosa-test/AccCPUConnector/', 'UD_GetDetBalance', jCustCodes, 'CPUConnUser', 'Nosa1234' ) ;
return res;
}
این تابع را می توانیم در قسمت کتابخانه javascript درج کنیم و در گردش کار، این تابع را با مقادیر مورد نظر خود (کد تفصیلی و کد حساب) صدا بزنیم. در این تابع از طریق RemoteCallAPI، پارامترهای کد تفصیلی و کد حساب به تابع UD_GetDetBalance در CPUConnector سیستم مالی نوسا پاس می شود. در مرحله آخر کافی است توسط تابع زیر مانده بدهی هر تفصیلی (مشتری) مورد نظر خود را به دست بیاوریم:
function WorkActionGetCustomerDebt() {
var debtInf=GetCustomerDebt ('02/001201', '112/92/60' ) ;
throw debtInf;
}
در این مثال، مانده بدهی شرکت نما سازه با کد تفصیلی '02/001201' و مرتبط با حساب چکهای بانکی نزد صندوق '112/92/60' خوانده و نمایش داده می شود.
پس ملاحظه کردید که توانستیم یک متد جدید (UD_GetDetBalance) را بصورت API ایجاد کنیم و در دسترس کلاینت های REST قرار دهیم.
پیاده سازی منطق تجاری (Business Rule) در CPUConnector
در مثالهایی که در بخشهای قبلی زده شد منطق تجاری در کلاینت تعیین می شد. به عبارت دیگر، نوع و نحوه ادامه کار پس از اجرای متد API در کلاینت تعیین می شود. اما این امکان وجود دارد که منطق تجاری در CPUConnector سرور سیستم مالی تعیین شود. به دو مثال در این مورد توجه کنید:
مثال 1: درخواست وام
فرض کنید یک متد API برای درخواست وام تعریف کرده ایم و می خواهیم طبق منطق تجاری زیر، وام را پرداخت کنیم:
منطق تجاری: اگر سابقه کاری درخواست کننده بیش از 3 سال باشد، آنگاه 5 ملیون تومان و در غیر این صورت 1 ملیون تومان پرداخت می شود.
در این مورد تابع API به شکل زیر خواهد بود:
function UD_LoanRequest(p) {
var years=GetPersonWorkYears(p);
if (years<3) {
PayLoan(5000000);
} else {
PayLoan(1000000);
}
}
توجه کنید که به این تابع، شماره استخدامی درخواست کننده به عنوان پارامتر پاس می شود و ابتدا از طریق یک متد دیگر API بنام GetPersonWorkYears سابقه کاری درخواست کننده استخراج می شود و سپس با توجه به آیین نامه (منطق تجاری) مبلغ تعیین شده از طریق یک متد دیگر API بنام PayLoan به او پرداخت می شود.
مثال 2: ثبت سفارش خرید
فرض کنید یک متد API برای ثبت سفارش خرید توسط مشتریان ایجاد کرده ایم. حال می خواهیم طبق قاعده زیر، سفارشها را ثبت کنیم:
قاعده تجاری: اگر مانده اعتبار مشتری بیشتر از 100 ملیون تومان باشد، سفارش ثبت و اقدام می شود و در غیر این صورت به مشتری پیغام کمبود اعتبار به مشتری ارسال می شود.
در این مثال، تابع API به شکل زیر است:
function UD_OrderProduct(p) {
var credit= GetCustomerCredit(p.customerCode);
If (credit < 100000000) {
SendFactor(p.data);
} else {
Throw “اعتبار شما کمتر از میزان مجاز است”
}
}
ملاحظه می کنید که به این تابع، کد مشتری و داده های مرتبط با خرید محصول (نام محصول، و میزان درخواست و ...) به شکل پارامتر پاس می شود و در ابتدا از طریق متد API بنام GetCustomerCredit میزان اعتبار مشتری استخراج می شود و سپس برمبنای قاعده تجاری، فروش انجام می شود و در غیر این صورت کمبود اعتبار به اطلاع مشتری می رسد.
توسعه خدمات API سیستم مالی به کلاینت های REST بصورت عام
در بخشهای قبلی و مثالهایی که زده شد، کلاینت REST با استفاده از ابزارهای سیستم مدیریت فرایندها ایجاد شده و از این طریق متدهای API سیستم مالی اجرا می شد. اما در اینجا لازم به توضیح است که این امکان منحصر به سیستم مدیریت فرایندها نیست و سازمانها می توانند با هر کلاینت REST پارامترهای لازم را به CPUConnetor بفرستند و متدهای API سیستم مالی را صدا بزنند.