در هر گردش کار، به مجموع ویژگیهای یک کار در هر لحظه، حالت یا وضعیت کار (WorkState) می گوییم. این مفهوم شامل تمام اطلاعات سیستمی کار از قبیل کلید کار، زمان شروع کار، نام آخرین وظیفه انجام شده، کاربر انجام دهنده آخرین وظیفه، زمان انجام آخرین وظیفه، نام وضعیت فعلی و ... و نیز مقادیر فیلدهای تعریف شده در گردش کار می باشد. از طرف دیگر گردش کارها ماهیتی سیال دارند و حالت کارها بطور مستمر در حال تغییر است. این تغییرات از طریق تراکنشها انجام می شود.
تعریف تراکنش
هر کار با انجام هر وظیفه، از یک حالت به حالت دیگر منتقل می شود. برای مثال ممکن است کاربر در فرم وظیفه، محتوا و مقدار بعضی از فیلدها را تغییر دهد یا اینکه از طریق تابع اجرایی تغییراتی در مقادیر فیلدها صورت پذیرد. بنابراین هر تراکنش در واقع نماینده انجام یک وظیفه و هم ارز با آن نماینده یک وضعیت کار (WorkState) خاص و مرتبط با آن وظیفه است.
توجه کنید: تنها تغییراتی که بر اثر اجرای یک وظیفه انجام می شود به عنوان تراکنش ثبت می شود. بنابراین تغییراتی که از طریق عملیات خاص و جزئیات انجام وظیفه رخ می دهد، در سیستم log نمی شود. در مورد ارسال پیام، اگر تغییر وضعیت رخ بدهد، چون در این نوع از پیامها، دو وظیفه خودکار انجام می شود، لذا این دو وظیفه هم در سیستم log می شود اما اگر پیام تنها مقادیر فیلدها را ویرایش کند این تغییرات ثبت نخواهد شد.
سابقه تراکنشها (History Log)
در پایگاه سیستم مدیریت فرایندها، همه تراکنشها با تمام جزئیات ثبت شده و قابل دسترسی است. بنابراین این امکان وجود دارد که روند تغییرات حالت یک کار را از آغاز تا هر وضعیت دلخواه مورد بررسی قرار دهیم و به اطلاعات کار، در هر تراکنش دست یابیم. حال سوال این است که اساسا کارکرد سابقه تراکنشها چیست و از این اطلاعات در کجا و به چه منظوری استفاده می شود؟
کاربرد سابقه تراکنشها در تصمیم گیری
در روند کارها در یک گردش کار، و بخصوص در وضعیتهای تصمیم گیر، گاهی اتفاق می افتد که تصمیم برای ادامه کار، به اطلاعات گذشته کار وابستگی پیدا می کند. یعنی اینکه حالتهای گذشته کار در انتخاب مسیر کار، تاثیر گذار و تعیین کننده است. در ادامه انواع اطلاعات log شده و کاربرد هر نوع به تفکیک توضیح داده شده است.
انواع اطلاعات سابقه تراکنشها
سابقه تراکنشها از دو سری اطلاعات تشکیل می شود: اطلاعات فیلدهای سیستمی و اطلاعات فیلدهای قابل تعریف
1) اطلاعات فیلدهای سیستمی
برای بدست آوردن اطلاعات تراکنشها از تابع WorkState.GetLogList(taskKey) استفاده می کنیم. این تابع فهرست تراکنشهای وظیفه با کد taskKey را به شکل آرایه ای از موجودات از نوع WorkLogInf در اختیار ما می گذارد که ویژگیهای آن شامل اطلاعات فیلدهای سیستمی به شر ح زیر است:
- کلید تراکنش گردش کار (Key)
- کلید کار (WorkKey)
- کلید وظیفه گردش کار (TaskKey)
- کلید منبع دیجیتال اصلی کار (DOKey)
- کلید کاربر (UserKey)
- زمان انجام تراکنش (DateTime)
- زمان بیداری (WakeTime) (فقط وقتی وجود دارد که رخداد دارای تاخیر باشد)
- نوع تراکنش (Kind) (0=کاربر 1=نرمافزار)
- نام رایانه کاربر (MachineName)
- یادداشت تراکنش گردش کار (Note)
- نوع آغاز کار برای تراکنش آغاز کار (ActivationKind) (0=تعیین نشده 1=دستی 2=از درون یک گردش کار 3=توسط برنامهریز ویندوز 4=ازدرون برنامه)
- کلید تراکنش آغازگر در کار مادر برای تراکنشهای آغاز زیرکارها (ActivationLogKey)
- مدت زمان انجام وظیفه (TaskDuration)
- هزینه انجام وظیفه (TaskCost)
- کیفیت انجام وظیفه (TaskQuality)
- مدت زمان کار تا این تراکنش (AggrDuration)
- هزینه کار تا این تراکنش (AggrCost)
- کیفیت کار تا این تراکنش (AggrQuality)
توضیح: اگر مقداری برای کلید وظیفه (taskKey) تعیین نکنید آنگاه فهرست تمام تراکنشهای کار، از آغاز تا وضعیت فعلی کار را خواهیم داشت.
1-1) کاربرد اطلاعات سیستمی در تصمیم گیری
اطلاعات فیلدهای سیستمی در مواردی می تواند در ادامه روند گردش کار تاثیر داشته باشد. به چند مثال در این زمینه توجه کنید:
مثال 1: نوع آغاز کار (دستی یا از درون یک گردش کار)
فرض کنید در یک گردش کار دموی محصولات، بعضی از کارها به شکل دستی و توسط مدیر عامل ایجاد می شود و بعضی از کارها از درون گردش کار فروش و به شکل خودکار آغاز می شود. حال فرض کنید می خواهیم کارهای دستی را به دلیل حساسیت بیشتر در اولویت قرار دهیم یا مثلا به یک کارشناس با تجربه تر واگذار کنیم. برای این کار می توانیم از تابع اجرایی زیر استفاده کنیم
function WorkTaskSetPriority() {
var transList=WorkState.GetLogList();
var startTask=transList[0];
var wKey=WorkState.WorkKey;
var prLevel="";
if (startTask.ActivationKind==1) {
prLevel="urgent"
} else {
prLevel="regular"
}
var data='<_RQST WorkKey="'+ wKey +'" PriorityScriptName="'+ prLevel +'"><!--_RQST-->';
WorkUtils.SetWorkPriority("", data);
}
برای آشنایی با نحوه این کار، در ادامه جزئیات سطرهای این تابع شرح داده می شود:
var transList=WorkState.GetLogList();
در ابتدای این تابع می خواهیم اطلاعات تراکنشهای وظیفه آغاز را به دست بیاوریم. برای این کار دو روش وجود دارد:
1- پاس کردن کلید وظیفه آغاز به تابع GetLogList
2- مقداردهی یک متغیر آرایه از فهرست تراکنشهای کار و استفاده از اولین عضو این آرایه به عنوان تراکنش آغاز
نکته مهم: اگر از ترتیب انجام وظیفه مطمئن باشیم (مانند وظیفه آغازین) بهتر است از روش دوم و در غیر این صورت باید حتما کلید وظیفه را بدست آورده و از آن طریق، تراکنشهای مرتبط با وظیفه را استخراج کنیم.
بدیهی است که در این مورد راه حل دوم بهتر است زیرا درگیر پیدا کردن کلید وظیفه نمی شویم لذا در این مثال از روش دوم استفاده شده و فهرست تراکنشهای کار در متغیر transList قرار داده می شود.
var startTask=transList[0];
در این سطر، همانطور که در بخش قبلی توضیح داده شد، عضو اول فهرست تراکنشهای کار یعنی تراکنش آغاز را در یک متغیر بنام startTask قرار می دهیم.
var wKey=WorkState.WorkKey;
var prLevel="";
برای تعیین اولویت کار نیاز به کلید کار و نام در برنامه سطح اولویت داریم که در اینجا کلید کار مشخص شده و سطح اولویت نیز تعریف شده است تا در سطرهای بعدی و بسته به شرایط مقداردهی شود.
if (startTask.ActivationKind==1) {
prLevel="urgent"
} else {
prLevel="regular"
}
var data='<_RQST WorkKey="'+ wKey +'" PriorityScriptName="'+ prLevel +'"><!--_RQST-->';
WorkUtils.SetWorkPriority("", data);
}
در این قسمت، با شرط گذاری روی مشخصه نوع آغاز کار (ActivationKind) ، تعیین شده است که اگر نوع آغاز کار از نوع "دستی" باشد ،به این کار، سطح اولویت خیلی فوری (urgent) و در غیر این صورت سطح اولویت عادی (regular) اختصاص داده شود. توجه داشته باشید که این سطوح اولویت قبلا و در سطح پایگاه تعریف شده است.
بخش انتهایی این قسمت نیز ابتدا در یک عبارت متنی به فرمت xml، پارامترهای "کلید کار" و "نام در برنامه سطح اولویت کار"، تعیین شده است و سپس در سطر انتهایی، این اولویت با استفاده از متد SetWorkPriority به کار جاری اختصاص داده شده است.
مثال 2: نام کامپیوتر کاربر
فرض کنید در یک گردش کار ارائه خدمات، یک سری کامپیوتر در محل سازمان، برای ثبت درخواست مشتریان در نظر گرفته شده است، حال فرض کنید یکی از این کامپیوترها برای کاربران با ویژگی خاص (مثلا افراد کم توان، کودک، ...) در نظر گرفته شده است. به این ترتیب با اعمال شرط روی نام کامپیوتر، می توانیم این نوع از درخواست ها را تشخیص داده و تصمیم مناسب برای این کاربران را بگیریم.
مثال 3: هزینه انجام وظیفه
در یک گردش کار پشتیبانی تیکتینگ ، برای توزیع بهتر و چابک شدن روند کارها می توانیم کارهایی را که هزینه تراکنش رفع اشکال آنها از یک مقدار کمتر است، بدون بررسی خاتمه دهیم اما کارهایی که مجموع هزینه زمان رفع اشکال آنها از یک حد خاص طولانی تر می شود را به کارتابل سرپرست پشتیبانی منتقل کنیم تا علت این قضیه بررسی گردد.
مثال 4: مدت زمان انجام کار
در گردش کار تامین و تدارکات، بویژه در شرایط تورمی، مدت زمان انجام تراکنشها بسیار اهمیت دارد. برای مثال مجموع مدت زمان کار تا قبل از وظیفه خرید (برای تراکنشهای بررسی درخواستهای خرید، استعلام، تامین اعتبار) فاکتور مهمی برای تصمیم به خرید می باشد. به این ترتیب با محاسبه مدت زمان انجام کار تا هر مرحله از کار می توانیم تصمیم مناسب را بگیریم.
مثال 5: نوع تراکنش (کاربر/ نرم افزار)
فرض کنید در یک گردش کار درخواست وام، پس از تراکنش ثبت درخواست وام، سیستم براساس آیین نامه وامها، این درخواست را بررسی می کند و اگر از حد مجاز کمتر بود، بطور اتوماتیک آن را برای تایید نهایی و درخواست به حسابداری منتقل می کند (تراکنش با رنگ آبی). و اما اگر مبلغ وام خارج از حد مجاز بود آنگاه برای بررسی بیشتر، به کارشناس مالی منتقل می کند. حال اگر کارشناس به هر دلیلی این درخواست را تایید کند آنگاه آن را با یک تراکنش دستی به حسابداری منتقل می کند(تراکنش مشخص شده با رنگ قرمز):
حال حسابدار می تواند براساس این که آخرین تراکنش از طریق سیستم (خودکار) بوده یا از طرف کارشناس مالی (به شکل دستی) بوده تصمیم بگیرد و مثلا درخواستهای خودکار را پرداخت کند و درخواستهای کارشناس مالی را بررسی کند و در صورت نیاز دستور اصلاح آن را بدهد.
نکته مهم: در این مثال می توانیم با استفاده از کد آخرین وظیفه انجام شده، وظیفه مورد نظر را شناسایی کنیم و نام وظیفه را به حسابدار نمایش دهیم اما دقت کنید که اولا این روش وابسته به کد وظیفه است و در صورت هرگونه ویرایش وظایف، کارکرد خود را از دست خواهد داد. ثانیا مفهوم خودکار و دستی بودن وظیفه، عامتر از محتوا و کارکرد وظیفه است. براین اساس می توانیم هرگونه ویرایش دلخواه در دیاگرام انجام دهیم و مثلا وظایف خودکار (یا دستی) دیگری را به روالهای کار اضافه کنیم اما در نهایت، عامل تعیین کننده، خودکار بودن یا دستی بودن وظیفه است.
سوال برای تفکر بیشتر 1: اگرچه این مثال تا حدی کاربرد این مشخصه را در سطح کار نشان می دهد اما به نظر می رسد کارکرد اصلی این مشخصه، در اندازه گیری شاخص اتوماسیون گردش کارها باشد که در سطح گردش کار سنجیده می شود. شما چه فکر می کنید؟
سوال برای تفکر بیشتر 2: بخشی از این موارد مثلا مثالهای 1 و 5 را می توانیم با تعریف فیلدهای مناسب و مقداردهی این فیلدها براساس شرایط، پیاده سازی کنیم. به نظر شما مزیت استفاده از log تراکنشها نسبت به روش استفاده از فیلدها چیست؟
2) اطلاعات فیلدهای قابل تعریف
در ابتدا که امکان سابقه تراکنشها ارائه شد، این امکان تنها برای فیلدهای سیستمی پیاده سازی شده بود و مقدار فیلدهای قابل تعریف از این قائده مستنثنا بودند اما در حال حاضر این قابلیت به سیستم اضافه شده و برمبنای آن، در هر تراکنش کار، مقدار فیلدهای قابل تعریف هم در سیستم ثبت (log) می شود. برای دستیابی به مقادیر فیلدها در تراکنش، یک پارامتر جدید بنام workLogKey به پارامترهای GetWorkState اضافه شده است. بنابراین، الگوی جدید تابع GetWorkState به شکل زیر است.
function GetWorkState(dbName, workKey, workLogKey):
توضیح این که پارامتر workLogKey کلید تراکنش است و لذا با داشتن کلید هر تراکنش، می توانیم مقدار فیلدهای قابل تعریف را قبل از تراکنش مورد نظر (درست در لحظه خروج وظیفه) در دست داشته باشیم.
دقت کنید: طبق تعریف و براساس توضیحات فوق، برای اینکه مقدار تغییر یافته فیلدها در اثر یک تراکنش را داشته باشیم باید تابع GetWorkState را روی تراکنش بعدی اعمال کنیم. چرا که ابتدا باید تراکنش مورد نظر انجام شود تا تغییرات را اعمال کند و سپس در لحظه خروج تراکنش بعدی، می توانیم این مقادیر را بازیابی نماییم. برای درک بهتر این موضوع، به شکل زیر توجه کنید:
در این گردش کار نمونه، اگر می خواهید مبلغ اصلاح شده وام را که در تراکنش (اصلاح مبلغ وام) ثبت شده، داشته باشید باید GetWorkState را روی تراکنش بعدی (تایید درخواست) اعمال کنید.
نکته بسیار مهم: برای اینکه بتوانیم مقدار فیلدهای قابل تعریف را در تراکنشها داشته باشیم، باید حتما وضعیت مبدا تراکنش مورد نظر (وضعیتی که تراکنش فوق از آن خارج می شود) قابلیت بازگشت داشته باشد. در غیر این صورت مقادیر فیلدهای قابل تعریف ثبت نمی شود و قابل بازیابی نخواهد بود. در مثال فوق، این قابلیت باید در وضعیت "در انتظار تایید سرپرست" وجود داشته باشد.
روش پیدا کردن کلید تراکنش (workLogKey)
همانطور که قبلا گفته شد، کلید تراکنش یکی از مشخصه های موجود WorkLogInf است. بنابراین برای پیدا کردن کلید یک تراکنش ابتدا باید از طریق GetLogList ، موجود WorkLogInf متناظر با آن تراکنش را بدست آوریم و سپس مشخصه کلید (Key) این موجود را استخراج کنیم.
1) GetLogList(taskKey) => sampleArray: WorkLogInf
2) sampleArray .Key => workLogKey
در اینجا ممکن است این سوال پیش بیاید که کارکرد قبلی تابع GetWorkState که مقدار فیلدها را در هر وضعیت بازمی گرداند، چه کاستی داشته و یا به بیان دیگر برای پاسخ به چه نیازی پارامتر کلید تراکنش به این تابع افزوده شده است؟ در ادامه با ضرورت و مزایای این قابلیت آشنا می شویم.
ضرورت ثبت فیلدهای قابل تعریف در سابقه تراکنشها
به دلیل احتمال تغییر مقدار فیلدها در تراکنشهای مختلف در جریان کار، ضرورت دارد که مقدار فیلدها در هر تراکنش ثبت شود. این مورد بویژه در وظایفی که در یک چرخه تکرار می شود بیشتر خود را نشان می دهد. به مثالهای زیر در این مورد توجه کنید:
مثال 1: اصلاح مقدار فیلد در وظایف متفاوت
در شکل زیر دیاگرام یک گردش کار درخواست وام را ملاحظه می کنید:
روال ثبت و تغییر مبلغ وام درخواستی در این گردش کار به شرح زیر است:
1) کارمند متقاضی وام در یک تراکنش که با شماره 1 مشخص شده، مبلغ درخواستی خود را ثبت می کند.
2) اگر مبلغ درخواستی کمتر از حد مجاز وام باشد بطور اتوماتیک برای پرداخت به کارتابل مدیر مالی منتقل می شود و درغیر این صورت درخواست برای بررسی اولیه به کارتابل سرپرست منتقل می شود.
3) سرپرست در صورت لزوم، دستور به اصلاح مبلغ وام می دهد و در پی آن، متقاضی در تراکنش دیگری که با شماره 2 مشخص شده است، مبلغ را اصلاح می کند. در انتها سرپرست درخواست را تایید و به کارتابل کارشناس مالی منتقل می کند.
4) کارشناس مالی مبلغ وام را با تشخیص خود یا اصلاح می کند و یا اینکه همان مبلغ را تایید و درخواست را برای پرداخت به کارتابل مدیر مالی می فرستد (وضعیتی که با رنگ زرد هایلایت شده است).
در این وضعیت و در حالت عادی، مدیر مالی فقط آخرین مبلغ ویرایش شده وام را مشاهده می کند اما شاید تمایل داشته باشد که از مبلغ درخواست اولیه در تراکنش 1 و مبلغ تغییر یافته در تراکنش 2 نیز آگاه شود. به این ترتیب مدیر مالی می تواند برآوردی از نوع و کیفیت نظارتهای سرپرست و کارشناس مالی داشته باشد و از این اطلاعات در سیاستگذاری ها و تصمیم گیرهای مدیریتی خود استفاده نماید.
توضیح: از آنجایی که هر دو تراکنش A و B از وضعیت در انتظار تایید سرپرست خارج شده اند لذا کافی فقط این وضعیت را قابل بازگشت نماییم.
تابع محاسباتی سابقه فیلد مبلغ وام
طبق توضیحاتی که قبلا داده شد، برای داشتن مبلغ درخواست اولیه (تراکنش 1) باید GetWorkState را روی تراکنش A (دستور اصلاح از طرف سرپرست) اعمال کنیم و برای داشتن مبلغ اصلاح شده وام (تراکنش 2)، باید این تابع را روی تراکنش B (تایید درخواست) اعمال نماییم. برای این کار می توانیم از تابع محاسباتی زیر استفاده کنیم:
function WorkFieldPrevLoanAmounts() {
var firstTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 14);
var secondTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 13);
var firstTransList=WorkState.GetLogList(firstTaskKey);
var secondTransList=WorkState.GetLogList(secondTaskKey);
var firstTransKey=firstTransList[0].Key;
var secondTransKey=secondTransList[0].Key;
var prevAmounts="";
var ws1=WorkUtils.GetWorkState("", WorkState.WorkKey, firstTransKey);
var ws2=WorkUtils.GetWorkState("", WorkState.WorkKey, secondTransKey);
prevAmounts+="مبلغ درخواست اوليه: " + ws1.loanAmount ;
prevAmounts+="\n" + "مبلغ تاييد شده توسط سرپرست: " + ws2.loanAmount ;
return prevAmounts;
}
در این مثال برای نمایش سابقه مبلغ وام ، یک فیلد محاسباتی از نوع متنی بنام prevAmounts تعریف شده است که محتوای این فیلد از طریق تابع محاسباتی بالا تولید و نمایش داده می شود. مطابق معمول برای درک بهتر این تابع، در ادامه، سطرهای تابع شرح داده می شود:
تعیین کلیدهای وظایف تراکنشهای قبلی
var firstTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 14);
var secondTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 13);
همانطور که قبلا گفته شد، در سه تراکنش زیر، مبلغ وام ثبت و یا ویرایش می شود:
1) تراکنش "ثبت درخواست وام" با کد 14 توسط متقاضی
2) تراکنش "اصلاح مبلغ وام" با کد 13 با نظر سرپرست و توسط متقاضی
3) تراکنش "تایید/ اصلاح مبلغ وام" با کد 9 توسط کارشناس مالی
حال فرض کنید در وضعیت پس از تراکنش سوم هستیم و می خواهیم سابقه مقدار مبلغ وام یعنی مبلغ درخواست اولیه و مبلغ اصلاح شده با نظر سرپرست را ملاحظه کنیم. بنابراین ابتدا باید کلید وظایف متناظر با این تراکنشها را بدست بیاوریم که در این دو سطر، این کلیدها از طریق متد GetWorkTaskKeyByCode انجام می شود.
بدست آوردن فهرست تراکنشهای وظایف قبلی
var firstTransList=WorkState.GetLogList(firstTaskKey);
var secondTransList=WorkState.GetLogList(secondTaskKey);
در این مرحله، فهرست تراکنشهای وظیفه "ثبت درخواست وام" در متغیر firstTransList و فهرست تراکنشهای وظیفه "اصلاح مبلغ وام" در متغیر secondTransList قرار می گیرد.
نکته بسیار مهم: دقت کنید که فهرست تراکنشها زمانی معنی دارد که تراکنش حداقل یک بار انجام شده باشد، بنابراین در هنگام استفاده از GetLogList حتما وجود یا عدم وجود آن را باید چک کنید چون ممکن است اساسا یک گردش کار در وضعیتی باشد که هنوز تراکنش مورد نظر شما اجرا نشده باشد.
بدست آوردن کلید تراکنشهای قبلی
var firstTransKey=firstTransList[0].Key;
var secondTransKey=secondTransList[0].Key;
از آنجایی که برای بدست آوردن WorkState تراکنشهای قبلی نیاز به کلید تراکنش داریم لذا در دو سطر فوق، کلید تراکنشها استخراج می شود. یادآوری می شود که آرایه فهرست تراکنشها از نوع WorkLogInf هستند که یکی از مشخصه های این موجود، کلید تراکنش می باشد.
نکته: همانطور که ملاحظه می کنید در این مثال از اندیس صفر فهرست تراکنشهای وظایف استفاده کرده ایم. دلیل این کار این است که این وظایف تنها یک بار انجام می شود ولذا آرایه تراکنشها تنها یک عضو دارد و اندیس آن تراکنش صفر است. اما در وظایفی که در حلقه تکرار می شود، ممکن است تکرارها و اندیس های بعدی نیز وجود داشته باشند و در نمایش سوابق تاثیرگذار باشند.
بدست آوردن حالت (WorkState) تراکنشهای قبلی
var prevAmounts="";
var ws1=WorkUtils.GetWorkState("", WorkState.WorkKey, firstTransKey);
var ws2=WorkUtils.GetWorkState("", WorkState.WorkKey, secondTransKey);
همانطور که می دانید، برای بدست آوردن مقدار فیلد در تراکنشهای قبلی باید حالت (WorkState) کار در این تراکنشها را داشته باشیم. بنابراین در این قسمت ابتدا یک متغیر بنام prevAmounts برای ذخیره مقدارهای قبلی مبلغ وام تعریف می شود و سپس در دو سطر بعدی از طریق متد GetWorkState، حالت (WorkState)های گردش کار در تراکنشهای قبلی مورد نظر استخراج و در متغیرهای ws1 و ws2 ذخیره می شود.
بدست آوردن مقدار مبلغ وام در تراکنشهای قبلی
prevAmounts+="مبلغ درخواست اوليه: " + ws1.loanAmount ;
prevAmounts+="\n" + "مبلغ تاييد شده توسط سرپرست: " + ws2.loanAmount ;
return prevAmounts;
در این مرحله مقدارهای قبلی فیلد مبلغ وام (loanAmount) از متغیرهای ws1 و ws2 استخراج می شود و به شکل یک عبارت متنی در متغیر prevAmounts قرار می گیرد و در نهایت همین متغیر توسط تابع بازگردانده (return) می شود. نمونه این عبارت را در فرم عمومی زیر مشاهده می کنید:
سوال برای تفکر بیشتر: نظر شما در مورد روش فوق یعنی نمایش سوابق یک فیلد در سطرهای متفاوت یک فیلد متنی چیست؟ آیا فکر می کنید روش دیگری برای این کار وجود دارد؟ روش پیشنهادی شما چه مزیتی نسبت به این روش دارد؟
مثال 2: تغییر مقدار فیلد در تکرارهای یک وظیفه
یک گردش کار پشتیبانی تیکتینگ را در نظر بگیرید که در بخشی از این گردش کار، چرخه ای وجود دارد که در آن، وظیفه رفع اشکال توسط کارشناس انجام می شود (شکل زیر):
در این قسمت، ابتدا کارشناس تراکنش 1 ) رفع اشکال) را انجام می دهد، سپس در تراکنش 2، مشتری فیدبک خود را اعلام می کند و پس از آن، سرپرست پشتیبانی بسته به فیدبک مشتری، و میزان تکمیل کار، تصمیم می گیرد کار را خاتمه دهد یا اینکه در تراکنش 3 برای رفع نواقص، مجددا به کارشناس برگرداند. بدیهی است که این چرخه، تا رضایت کامل مشتری و سرپرست ممکن است چند بار تکرار شود و در هر تکرار این حلقه، فیلدهای زیر مقداردهی شوند:
- شرح انجام کار توسط کارشناس پشتیبانی
- نظر یا بازخورد مشتری در مورد کار انجام شده
- توضیح سرپرست در مورد نواقص باقیمانده و رفع آنها
بدیهی است که ثبت و نگهداری مقدار این فیلدها در هر تکرار (تراکنش) برای گزارشگیری و نظارت بر اجرای گردش کار، بسیار مفید و ضروری است. برای این کار کافی است یک آرایه محاسباتی با نام debugHistory با سطرهای متناظر با فیلدهای فوق تعریف کنیم و سپس مقدارهای فیلدهای هر تکرار را در سطرهای این آرایه نمایش دهیم. برای این کار از تابع محاسباتی زیر استفاده می کنیم:
function WorkFieldDebugHist() {
var firstTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 14);
var secondTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 23);
var thirdTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 25);
var firstTransList=WorkState.GetLogList(firstTaskKey);
var secondTransList=WorkState.GetLogList(secondTaskKey);
var thirdTransList=WorkState.GetLogList(thirdTaskKey);
var debugReps=firstTransList.length;
var hist=[];
for (var i=0; i
hist={};
var firstTransKey=firstTransList.Key;
var ws1=WorkUtils.GetWorkState("", WorkState.WorkKey, firstTransKey);
if (i>0) {
hist[i-1].supervisorNote=ws1.supervisorNote;
}
if (secondTransList) {
var secondTransKey=secondTransList.Key;
var ws2=WorkUtils.GetWorkState("", WorkState.WorkKey, secondTransKey);
hist.workDone=ws2.workDone;
}
if (i>0) {
var thirdTransKey=thirdTransList[i-1].Key;
}
var ws3=WorkUtils.GetWorkState("", WorkState.WorkKey, thirdTransKey);
hist.custFeedback=ws3.custFeedback;
}
return hist;
}
در ادامه به تشریح جزئیات این تابع می پردازیم:
بدست آوردن کلید وظایف مرتبط با تراکنشهای قبلی
var firstTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 14);
var secondTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 23);
var thirdTaskKey=WorkUtils.GetWorkTaskKeyByCode(WorkState.WorkflowKey, 25);
در این مرحله، کلید وظایف مورد نظر از طریق کد آنها بدست می آید.
بدست آوردن فهرست تراکنشهای هر وظیفه
var firstTransList=WorkState.GetLogList(firstTaskKey);
var secondTransList=WorkState.GetLogList(secondTaskKey);
var thirdTransList=WorkState.GetLogList(thirdTaskKey);
در این مرحله فهرست تراکنشهای وظایف استخراج می شود. با توجه به امکان تکرار این وظایف، فهرست تراکنشهای هر وظیفه می تواند بیش از یک عضو داشته باشد.
بدست آوردن تعداد تکرارهای حلقه رفع اشکال
var debugReps=firstTransList.length;
در این مرحله تعداد تکرار حقه رفع اشکال را از طریق تعداد تراکنش 1 (انجام رفع اشکال) بدست می آوریم. در واقع تعداد باری که کارشناس عمل رفع اشکال را انجام می دهد تعیین کننده تعداد تکرار حلقه می باشد.
تعریف یک متغیر آرایه و ایجاد یک حلقه برای مقداردهی به این آرایه
var hist=[];
for (var i=0; i
….
}
در این مرحله، یک متغیر آرایه بنام hist تعریف می کنیم و اجزای این آرایه را همنام و متناظر با اجزای آرایه debugHistory مقدار دهی می کنیم. جزئیات فیلد آرایه محاسباتی debugHistory به شرح زیر است:
debugHistory (سابقه رفع اشکالها):
- workDone (انجام رفع اشکال)
- custFeedback(فیدبک مشتری)
- supervisorNote(یادداشت سرپرست)
مقداردهی این آرایه داخل یک حلقه forو برای هر تکرار از تراکنشها، یک سطر به این آرایه اضافه می کنیم. در ادامه به محتویات این حلقه می پردازیم:
ایجاد یک سطر جدید در آرایه
hist={};
یکی از روشهای مقدار دهی آرایه ها این است که ابتدا یک سطر جدید ایجاد می کنیم و سپس اجزای این سطر را مقداردهی می کنیم. بنابراین باید در ابتدای حلقه و در هر تکرار، یک سطر جدید ایجاد کنیم.
مقداردهی یادداشت سرپرست (supervisorNote)
var firstTransKey=firstTransList.Key;
var ws1=WorkUtils.GetWorkState("", WorkState.WorkKey, firstTransKey);
یادداشت سرپرست در تراکنش ارجاع مجدد به کارشناس ثبت می شود. حال طبق این اصل که برای بدست آوردن سابقه هر تراکنش، باید حالت کار (WorkState)را در خروجی وظیفه بعدی استخراج کنیم. در نتیجه باید سابقه تراکنش "ارجاع مجدد به کارشناس" را در حالت کار (WorkState) مرتبط با وظیفه "انجام رفع اشکال" استخراج کنیم. توجه کنید که در دیاگرام، وظیفه "انجام رفع اشکال"، پس از وظیفه "ارجاع مجدد به کارشناس" انجام می شود. به این ترتیب، در این قسمت ابتدا کلید تراکنش 1 (انجام رفع اشکال) در متغیر firstTransKey ذخیره می شود و سپس حالت کار در لحظه قبل از انجام این تراکنش استخراج و در متغیر ws1 قرار می گیرد.
if (i>0) {
hist[i-1].supervisorNote=ws1.supervisorNote;
}
در این مرحله، محتوای یادداشت سرپرست در ستون supervisorNote از آرایه hist مقداردهی می شود. در اینجا ممکن است این سوال پیش بیاید که چرا مقداردهی این جزء آرایه از تکرار دوم به بعد ( شرط i>0 ) انجام می شود. دقت کنید که یادداشت سرپرست در تراکنش ارجاع مجدد به کارشناس ثبت می شود و در تکرار اول این حلقه، ارجاع مجدد معنی ندارد ولذا این یادداشت برای تکرارهای بعدی رفع اشکال معنی دار است و به همین دلیل هم اندیس i-1 از آرایه مقداردهی می شود. برای مثال یادداشت سرپرست در انتهای تکرار اول، منجر به تکرار رفع اشکال در تکرار دوم می شود در نتیجه در تکرار دوم تراکنش "رفع اشکال" می توانیم یادداشت سرپرست در تکرار اول را مقداردهی کنیم.
مقداردهی شرح رفع اشکال (workDone)
if (secondTransList) {
var secondTransKey=secondTransList.Key;
var ws2=WorkUtils.GetWorkState("", WorkState.WorkKey, secondTransKey);
hist.workDone=ws2.workDone;
}
طبق روالی که قبلا هم توضیح داده شد، برای مقداردهی ستون "شرح رفع اشکال"، باید حالت کار را در لحظه اجرای تراکنش بعدی (فیدبک مشتری) داشته باشیم. بنابراین در این قسمت ابتدا کلید تراکنش 2 (فیدبک مشتری) را بدست می آوریم و سپس حالت کار در لحظه انجام این تراکنش را با استفاده از GetWorkState استخراج و در متغیر ws2 قرار می دهیم. در انتها، ستون شرح رفع اشکال از آرایه را با مشخصه workDone از ws2 مقداردهی می کنیم.
مقداردهی فیدبک مشتری (custFeedback)
if (i>0) {
var thirdTransKey=thirdTransList[i-1].Key;
}
var ws3=WorkUtils.GetWorkState("", WorkState.WorkKey, thirdTransKey);
hist.custFeedback=ws3.custFeedback;
در این مرحله برای مقداردهی ستون فیدبک مشتری، ابتدا کلید تراکنش بعدی (ارجاع مجدد به کارشناس) را بدست می آوریم و سپس حالت کار در لحظه اجرای این تراکنش را استخراج و در متغیر ws3 قرار می دهیم. در انتها ستون فیدبک مشتری را با مشخصه custFeedBack از ws3 مقداردهی می کنیم.
توضیح: شرط i>0 در اینجا بخاطر این است که همانطور که قبلا هم توضیح داده شد، در تکرار اول حلقه، تراکنش ارجاع مجدد کارشناس وجود ندارد و ارجاع مجدد از تکرار دوم به بعد معنی پیدا می کند.
بازگشت آرایه hist به عنوان مقدار نهایی تابع
return hist;
در انتها مقدار متغیر hist به عنوان خروجی تابع بازگردانده می شود و این خروجی، آرایه محاسباتی debugHistory را مقداردهی می کند.
سوال برای تفکر بیشتر : راه حلی که تا قبل از این برای ثبت سوابق فیلدها در یک حلقه تکرار استفاده می شد، تعریف یک آرایه از نوع داده و ثبت اطلاعات هر تکرار (تراکنش) در ستونهای یک سطر آرایه بوده است. به نظر شما این راه حل چه نکات منفی نسبت به راه حل استفاده از log تراکنشها دارد؟