أدوات MCP
ملفات العطاء والمهام الخلفية
أدوات MCP لتوليد ملفات التقديم (ملف الرد وملف المرفقات وخطاب التغطية) ومتابعة المهام الخلفية للملفات الكبيرة.
تولد هذه الأدوات الملفات التي تقدمها مع العطاء: ملف رد نوبكو، وملف مرفقات نوبكو، وخطاب التغطية العربي. يبنى كل ملف مما حفظته في المنصة: أسعار بنود المنافسة، والبنود المعلمة بالمشاركة، والمنتجات المختارة لها، وعروض الأسعار التي أنشأتها. وأربع أدوات أخرى تتابع المهام الخلفية للملفات التي تستغرق وقتا. وتشرح ملفات العطاء كيف تنشأ الملفات نفسها من التطبيق. وللعروض على بوابة iNUPCO نفسها يوجد دليل خطوة بخطوة.
priced_items_not_participating، وتعيد علامته `tender_item_participation_set_batch`. والبند المسعر بصفر يستبعد مهما كانت علامته ويحسب zero_priced_items، فالصفر ليس سعر عطاء.تأخذ الأدوات الثلاث اختياريا quotation_ids، فتغطي الملفات البنود التي تسعرها تلك العروض وتشير إليها وحدها. وأسعار العطاء المحفوظة هي المرجع دائما: عرض سعر محدد يذكر سعرا مختلفا يبلغ عنه التقرير ولا يغير الملف. وتأخذ كل أداة report: true لتعيد تقريرا بصيغة JSON بدل الملف، فاستخدمه أولا حين تريد معرفة ما ينقص. والأدوات الثلاث للخطة الاحترافية وخطة المؤسسات.
| الأداة | ما تفعله |
|---|---|
| tenders_nupco_response_fill | تعبئة ملف رد نوبكو |
| tenders_nupco_attachments_fill | توليد ملف مرفقات نوبكو |
| tenders_cover_letter_pdf | توليد خطاب تغطية المنافسة |
| generation_jobs_list | عرض المهام الخلفية |
| generation_jobs_get | عرض مهمة خلفية |
| generation_jobs_part | تنزيل جزء من مهمة خلفية |
| generation_jobs_cancel | إلغاء مهمة خلفية |
ملفات العطاء الثلاثة
لا تغير هذه الأدوات سجلاتك: تقرأ أسعارك المحفوظة وتولد ملفا منها.
tenders_nupco_response_fill
يعبئ ملف الرد الذي نزلته من بوابة نوبكو بأسعارك المحفوظة والضريبة والمنتجات المختارة لمنافسة واحدة، ويعيد الملف نفسه معبأ. والقالب يجب أن يكون ملف البوابة نفسه لهذه المنافسة: لا يصنع من الصفر، ويرفض ملف منافسة أخرى.
للقراءة فقط · الصلاحية bids.read · الأدوار: المالك، المدير، المبيعات، المشتريات · الخطة الاحترافية وخطة المؤسسات
| المعامل | النوع | مطلوب | الوصف |
|---|---|---|---|
tender_id | integer | نعم | معرف المنافسة، ويأتي من tenders_list. |
template_base64 | string | نعم | ملف الرد بصيغة .xlsx كما نزل من بوابة نوبكو، بترميز base64. السقف العملي نحو 3 ميغابايت لأن الخادم يرفض أي طلب يتجاوز نحو 4.5 ميغابايت. وعلى واتساب يمرر المساعد مرجع المرفق بدل المحتوى. |
filename | string | لا | اسم الملف الأصلي، حتى 300 حرف. |
vat_percent | number | لا | نسبة الضريبة الافتراضية، من 0 إلى 100، للصفوف التي لا تحدد منتجاتها المختارة نسبة. تؤخذ 15 إن حذفت. ونسبة المنتج نفسه تتقدم دائما. |
quotation_ids | integer[] | لا | معرفات عروض الأسعار، وتأتي من `tender_quotations_list` وهي عادة العروض المعتمدة. يغطي الملف البنود التي تسعرها هذه العروض وحدها ويشير إليها بالذات. يجب أن يكون كل معرف لعرض سعر في مؤسستك على هذه المنافسة، وإلا رد الخادم بـ400 quotation_tender_mismatch. من 1 إلى 5000 معرف. وإن حذفت الحقل شمل الملف كل بند مسعر مشارك في المنافسة. |
report | boolean | لا | true يعيد تقرير التعبئة بصيغة JSON مع رابط لتنزيل الملف بدل الملف نفسه. |
{
"tender_id": 48213,
"template_base64": "UEsDBBQABgAIAAAAIQAk3kP1...",
"filename": "NPT0024-26-response.xlsx",
"vat_percent": 15,
"quotation_ids": [
5312,
5313
],
"report": true
}ما يعيده: الملف المعبأ (filename وcontent_type وsize_bytes وbase64). ومع report: true كائن فيه filename وdownload_url وتقرير التعبئة report.
- تعبأ صفوف البنود المسعرة بأكثر من صفر والمعلمة بالمشاركة فقط. والصفوف بلا سعر محفوظ تبقى كما هي وتعود مخفية لا محذوفة، فتقرأها بوابة نوبكو عند الرفع. والصف الذي لا تستطيع التعبئة البت فيه (رمز مادة تشترك فيه عدة صفوف، أو حقل إلزامي ناقص، أو منتج غير مختار) يبلغ عنه التقرير برقم صفه دون تخمين، ويبقى ظاهرا.
- يحمل
reportالحقولtemplate_rowsوfilled_rowsوhidden_rowsوissuesوmissing_mandatory(الصف والرمز والحقول الناقصة) وnot_applicable(بنود الخدمات: الخلايا التي تصف سلعا ولا تنطبق عليها، كالمصنع ورقم الكتالوج، وليست ناقصة) وunmatched_priced_codes، وأعدادpriced_items_not_participatingوzero_priced_itemsوpriced_items_outside_selection. ومعquotation_idsيضافquotation_scopeومشكلات الصفوف:quotation_price_mismatch(عرض محدد يذكر سعرا غير سعر العطاء المحفوظ، والمكتوب في الملف هو سعر العطاء) وquotation_not_approved(عرض ما زال مسودة) وmultiple_quotations(عدة عروض محددة تغطي بندا واحدا، ويعتمد أحدث المعتمدة منها). - يرد الخادم بـ400 مع
wrong_template_tenderإن كان الملف لمنافسة أخرى، وinvalid_file_typeإن لم يكن xlsx، وmissing_columnsوتسميهاdetail، وno_participating_itemsإن وجدت أسعار ولا بند معلم بالمشاركة، وno_bid_pricingإن لم يسعر بند بأكثر من صفر، وquotation_scope_emptyإن لم تسعر العروض المحددة أي بند من المنافسة. والمنافسة التي لا تراها مؤسستك ترد بـ404tender_not_found.
tenders_nupco_attachments_fill
يبني حزمة مرفقات نوبكو لمنافسة واحدة من الصفر: الملف النصي المفصول بعلامات تبويب الذي تقبله بوابة SRM، وأعمدته تسمي ملفات PDF، مع كل ملف PDF يذكره بالاسم المذكور بالضبط، فتكون الملفات المفكوكة هي مجموعة الرفع. يبنى في الخلفية، وتنتظره الأداة وتعيد الملف أو المهمة إن طال.
للقراءة فقط · الصلاحية bids.read · الأدوار: المالك، المدير، المبيعات، المشتريات · الخطة الاحترافية وخطة المؤسسات
| المعامل | النوع | مطلوب | الوصف |
|---|---|---|---|
tender_id | integer | نعم | معرف المنافسة، ويأتي من tenders_list. |
rfx_response_number | string | نعم | رقم رد RFx في SRM كما يظهر على العطاء في بوابة نوبكو، مثل 5000061479. يطبع على كل سطر في الملف فيجب أن يكون الرقم الحقيقي، فاطلبه من صاحب العطاء ولا تخترعه. نص عادي من 1 إلى 40 حرفا. |
quotation_ids | integer[] | لا | معرفات عروض الأسعار، وتأتي من `tender_quotations_list` وهي عادة العروض المعتمدة. يغطي الملف البنود التي تسعرها هذه العروض وحدها ويشير إليها بالذات. يجب أن يكون كل معرف لعرض سعر في مؤسستك على هذه المنافسة، وإلا رد الخادم بـ400 quotation_tender_mismatch. من 1 إلى 5000 معرف. وإن حذفت الحقل شمل الملف كل بند مسعر مشارك في المنافسة. |
report | boolean | لا | true يعيد المهمة مع تقريرها، وفيه الملفات الناقصة لكل سطر وقائمة الملفات وروابط الأجزاء، بدل تسليم الملف. |
wait_seconds | integer | لا | عدد الثواني التي تنتظر فيها الأداة اكتمال الحزمة قبل أن تعيد المهمة: الافتراضي 40 والأقصى 120. والحزمة الصغيرة تنتهي عادة خلالها. |
{
"tender_id": 48213,
"rfx_response_number": "5000061479",
"quotation_ids": [
5312,
5313
],
"wait_seconds": 60
}ما يعيده: إن اكتملت الحزمة خلال wait_seconds في ملف ZIP واحد أقل من 4 ميغابايت جاء الملف (filename وcontent_type وsize_bytes وbase64) مع report. وإلا جاءت المهمة: job_id وstatus وprogress وparts (لكل جزء download_url صالح لساعة بعد نجاح المهمة) وreport وnext_step.
- تأتي الحزمة الكبيرة في عدة أجزاء ZIP (نحو 47 ميغابايت للجزء)، فنزل كل جزء بـ`generation_jobs_part` وفك الأجزاء كلها في مجلد واحد. والحزمة التي ما زالت تبنى ترد بـ
job_idوتقدمها وتواصل البناء في الخلفية، فتابعها بـ`generation_jobs_get` أو تجدها في بطاقة الملفات المنشأة في صفحة عروض الأسعار. - تبنى حزمة واحدة لكل منافسة في الوقت نفسه. فإن كانت حزمة قيد البناء ردت الأداة بتلك المهمة مع
already_running: true، وقد تكون لتحديد مختلف أو لرقم RFx مختلف. ألغها بـ`generation_jobs_cancel` لتبدأ من جديد. - كل سطر في الملف لبند مسعر بأكثر من صفر ومعلم بالمشاركة، وعليه خيار التغيير C. ولكل بند تذكر الحزمة ملف عرض السعر الخاص به، وخطاب غلاف (ملخص سطر عرض السعر في صفحة واحدة يليه كتالوج المنتج المحفوظ، وإن لم يوجد كتالوج محفوظ خرج الغلاف وحده ونبه التقرير بـ
catalog_pages_missing)، ومستند MDMA أو هيئة الغذاء والدواء، وهو الشهادة المحفوظة أو خطاب امتثال يولد إن كان المنتج قيد التسجيل أو بلا شهادة، ويذكر في عمودي شهادات SFDA وملحق MDMA معا. وكل ملف PDF اسمهitem-<serial>-<slot>.pdf(والخاناتquoteوcatalogوsfdaوmdma) وطوله أقل من 40 حرفا. - يسرد
reportلكل سطر ما ينقصه فيmissing_filesوكل ملف فيfiles، وفيnot_applicable_filesخانات بنود الخدمات التي لا تحمل كتالوجا ولا شهادة (ليست ناقصة)، مع أعداد الاستبعاد ومشكلات العروض نفسها المذكورة في ملف الرد. وتفشل الفحوص السريعة قبل بدء أي مهمة:invalid_rfx_response_numberوno_bid_pricingوno_participating_itemsوquotation_scope_empty، والمنافسة التي لا تراها مؤسستك ترد بـ404tender_not_found.
tenders_cover_letter_pdf
يولد خطاب التغطية العربي الذي يقدمه المورد مع عطائه، بصيغة PDF. يخاطب الجهة المشترية، ويبين العرض مع تفصيل الضريبة، ويتضمن إقرار الالتزام بالأنظمة. وعدد البنود والمبالغ تقرأ من عطائك المحفوظ ولا تكتب.
للقراءة فقط · الصلاحية bids.read · الأدوار: المالك، المدير، المبيعات، المشتريات · الخطة الاحترافية وخطة المؤسسات
| المعامل | النوع | مطلوب | الوصف |
|---|---|---|---|
tender_id | integer | نعم | معرف المنافسة، ويأتي من tenders_list. |
letter_number | string | لا | رقم خطابك الصادر كما في سجل مراسلات مؤسستك، مثل DPC-1909، ويطبع في سطر رقم الخطاب. إن حذف ترك السطر. لا تخترع رقما: المنصة لا تحتفظ بسجل للمراسلات الصادرة، ورقم مختلق قد يتعارض مع رقم حقيقي عندك. حتى 60 حرفا. |
recipient | string | لا | سطر المخاطب بالعربية. إن حذف خوطبت الجهة المشترية المذكورة في المنافسة. حتى 300 حرف. |
recipient_department | string | لا | سطر المخاطب الثاني بالعربية، مثل إدارة العقود والمشتريات. حتى 300 حرف. |
notes | string | لا | فقرة عربية إضافية تطبع قبل الخاتمة، حتى 1000 حرف. |
quotation_ids | integer[] | لا | معرفات عروض الأسعار، وتأتي من `tender_quotations_list` وهي عادة العروض المعتمدة. يغطي الملف البنود التي تسعرها هذه العروض وحدها ويشير إليها بالذات. يجب أن يكون كل معرف لعرض سعر في مؤسستك على هذه المنافسة، وإلا رد الخادم بـ400 quotation_tender_mismatch. من 1 إلى 5000 معرف. وإن حذفت الحقل شمل الملف كل بند مسعر مشارك في المنافسة. |
report | boolean | لا | true يعيد عدد البنود والعرض والضريبة والإجمالي بصيغة JSON مع رابط لتنزيل الملف بدل الملف نفسه. |
{
"tender_id": 48213,
"letter_number": "DPC-1909",
"recipient_department": "إدارة العقود والمشتريات",
"quotation_ids": [
5312,
5313
],
"report": true
}ما يعيده: الخطاب بصيغة PDF (filename وcontent_type وsize_bytes وbase64). ومع report: true كائن فيه filename وdownload_url والتقرير report وفيه item_count وsubtotal وvat وtotal وvat_review وquotation_scope وquotation_price_review.
- الخطاب بالعربية وحدها ولا يعدد المستندات المرفقة، لأن المنصة لا ترى ما رفع إلى البوابة. وهو يصلح لأي منافسة، لا لمنافسات نوبكو وحدها.
- يذكر الخطاب البنود المسعرة بأكثر من صفر والمعلمة بالمشاركة (ضمن
quotation_idsإن أرسلتها). وتجمع الضريبة لكل سطر بنسبة المنتج المختار للبند: 15٪ إن لم يحدد المنتج نسبة أو لم يختر منتج، و0٪ للمنتج الذي يعفيه الكتالوج، كما يحسبها ملف رد نوبكو بالضبط، فلا يتناقض الملفان. والإجمالي المذكور يشمل الضريبة ويكتب كذلك بالحروف، فوق جدول يفصل العرض عن الضريبة. - راجع
vat_reviewقبل الإرسال: يسرد السطور التي تناقض نسبة ضريبتها وسم المنتج الطبي، في الاتجاهين (منتج غير طبي معفى وهذا ينقص العطاء، أو منتج طبي بالنسبة العادية)، مع الضريبة التي سيغيرها كل سطر. والخطاب يطبع النسبة نفسها التي يكتبها ملف الرد، فصحح ضريبة المنتج في الكتالوج أولا. ويسردquotation_price_reviewالعروض المحددة التي تذكر سعر وحدة غير سعر العطاء المحفوظ الذي يجمعه الخطاب. - يرد الخادم بـ400 مع
no_participating_itemsإن وجدت أسعار ولا بند معلم بالمشاركة، وno_bid_pricingإن لم يسعر بند بأكثر من صفر، وquotation_scope_emptyإن لم تسعر العروض المحددة أي بند من المنافسة. والمنافسة التي لا تراها مؤسستك ترد بـ404tender_not_found.
المهام الخلفية
نوعان من الملفات أكبر من أن يبنيا في طلب واحد، فيبنيان في الخلفية مهمتين: حزمة مرفقات نوبكو (nupco_attachments، تبدأها `tenders_nupco_attachments_fill`) وحزمة عروض الأسعار (quotation_packages، تبدأها `quotation_packages_bundle`). حالة المهمة queued أو running أو succeeded أو failed أو cancelled. والمهام ملك المؤسسة فترى ما بدأه زملاؤك، وتبقى المهمة المنتهية 24 ساعة. تبنى حزمة واحدة لكل منافسة، وحزمة عروض واحدة لكل عضو، في الوقت نفسه. والملف الجاهز جزء ZIP أو أكثر، فافتح كل الأجزاء في مجلد واحد.
generation_jobs_list
يعرض مهام مؤسستك الخلفية في آخر 24 ساعة، الأحدث أولا، أيا كان من بدأها، لكل مهمة حالتها وتقدمها. استخدمه لتجد مهمة بدأها زميلك أو بدأتها أنت ونسيت معرفها.
للقراءة فقط · الصلاحية bids.read أو quotations.read · الأدوار: المالك، المدير، المبيعات، المشتريات، المشاهد · الخطة الاحترافية وخطة المؤسسات
| المعامل | النوع | مطلوب | الوصف |
|---|---|---|---|
tender_id | integer | لا | يعرض مهام هذه المنافسة وحدها. |
kind | string | لا | يعرض مهام نوع واحد: nupco_attachments لحزم المرفقات، أو quotation_packages لحزم عروض الأسعار. |
ما يعيده: jobs: قائمة، لكل مهمة job_id وkind وstatus وprogress (done وtotal وunit) وparts (الرقم والاسم والحجم) وexpires_at بعد النجاح وerror عند الفشل وتلميح next_step. بلا تقرير ولا روابط تنزيل، فاقرأ المهمة الواحدة بـgeneration_jobs_get.
- تعيد الأداة 30 مهمة على الأكثر. ويرى المفتاح الأنواع التي تغطيها صلاحياته:
bids.readلحزم المرفقات وquotations.readلحزم عروض الأسعار، وطلب نوع لا تغطيه صلاحياتك يرد بـ403.
generation_jobs_get
يقرأ مهمة واحدة: حالتها وتقدمها، وبعد نجاحها تقريرها وأجزاء ZIP. ويمكنه أن ينتظر اكتمالها حتى 120 ثانية. وتسلم أجزاء المهمة المنتهية بـgeneration_jobs_part.
للقراءة فقط · الصلاحية bids.read أو quotations.read · الأدوار: المالك، المدير، المبيعات، المشتريات، المشاهد · الخطة الاحترافية وخطة المؤسسات
| المعامل | النوع | مطلوب | الوصف |
|---|---|---|---|
job_id | string | نعم | معرف المهمة (UUID)، وهو job_id في رد الأداة التي بدأتها أو في generation_jobs_list. |
wait_seconds | integer | لا | ينتظر الخادم اكتمال المهمة حتى هذا العدد من الثواني، من 0 إلى 120. الافتراضي 0: يرد فورا. |
ما يعيده: المهمة: job_id وkind وstatus وprogress وparts (لكل جزء index وfilename وsize_bytes وdownload_url صالح لساعة)، وwaiting إن لم يحركها أحد منذ فترة، وبعد النجاح report وexpires_at، وعند الفشل error برمزه وتفصيله، وnext_step. وعلى واتساب تحذف الروابط، فاستخدم generation_jobs_part لإرسال الجزء مستندا.
- قراءة المهمة تحرك عملها أيضا: إن لم يكن أحد يعمل عليها بدأت القراءة مرحلة العمل التالية. والمهمة التي لم يحركها شيء 30 دقيقة تفشل برمز
stalled. - تقرير حزمة المرفقات هو الموصوف في أداتها. وتقرير حزمة عروض الأسعار يسمي كل عرض ضمن الحزمة مع الجزء الذي فيه، وكل عرض لم ينتج شيئا برقمه وسببه:
not_foundأوrender_failedأوtoo_large. - المهمة المجهولة أو التي تخص مؤسسة أخرى ترد بـ404، والمفتاح الذي لا يحمل صلاحية نوع المهمة يرد بـ403:
bids.readلحزمة المرفقات وquotations.readلحزمة عروض الأسعار.
generation_jobs_part
يسلم جزء ZIP واحدا من مهمة انتهت، برقم الجزء كما تسرده generation_jobs_get. على واتساب يصل الجزء إلى الشخص مستندا، وفي غيرهما يأتي بترميز base64 إن كان أقل من 4 ميغابايت، وإلا جاء رابط تنزيل صالح لساعة.
للقراءة فقط · الصلاحية bids.read أو quotations.read · الأدوار: المالك، المدير، المبيعات، المشتريات، المشاهد · الخطة الاحترافية وخطة المؤسسات
| المعامل | النوع | مطلوب | الوصف |
|---|---|---|---|
job_id | string | نعم | معرف المهمة (UUID). |
part | integer | لا | رقم الجزء بدءا من 1، الافتراضي 1. والجزء غير الموجود يرد بـ404. |
ما يعيده: الجزء ملفا (filename وcontent_type وsize_bytes وbase64) إن كان أقل من 4 ميغابايت. وإلا filename وsize_bytes وdownload_url صالح لساعة مع ملاحظة بأن الملف أكبر من أن يضمن في الرد.
- الجزء يسلم في كل استدعاء، فالحزمة ذات الأجزاء الثلاثة تحتاج ثلاثة استدعاءات، وتفك الأجزاء كلها في مجلد واحد.
- المهمة التي لم تنته ترد بـ409
job_not_finished، فلا توجد الأجزاء إلا بعد النجاح. وتلزم صلاحية نوع المهمة:bids.readلحزمة المرفقات وquotations.readلحزمة عروض الأسعار، وغيرها يرد بـ403.
generation_jobs_cancel
يوقف مهمة في الانتظار أو قيد العمل. تحذف الأجزاء التي بنيت حتى الآن، وتبقى المهمة في القائمة ملغاة 24 ساعة. استخدمه قبل بدء حزمة مرفقات جديدة لمنافسة حزمتها قيد البناء، أو حزمة عروض جديدة وآخر حزمة لك ما زالت تبنى.
يحذف بيانات أو يستبدلها · الصلاحية bids.read أو quotations.read · الأدوار: المالك، المدير، المبيعات، المشتريات · الخطة الاحترافية وخطة المؤسسات
| المعامل | النوع | مطلوب | الوصف |
|---|---|---|---|
job_id | string | نعم | معرف المهمة (UUID). |
ما يعيده: المهمة بعد الإلغاء، وحالتها cancelled.
- المهمة التي لم تعد في الانتظار ولا قيد العمل ترد بـ409
job_not_activeمع المهمة نفسها. وتلزم صلاحية نوع المهمة:bids.readلحزمة المرفقات وquotations.readلحزمة عروض الأسعار. - يتوقف العمل الجاري عند أول حفظ له، وما بني من الأجزاء يحذف ولا يمكن استرجاعه.