schoolos-report-ar
> متى تُستعمل: "Arabic RTL PDF and Excel exports: renderpdf, ExcelService, print frame. Trigger: PDF, Excel, export, WeasyPrint, A3. تقرير، كشف، شهادة، تصدير، طباعة"
SKILL.md.claude/skills/schoolos-report-ar/SKILL.md
GitHubمتى تُستعمل: "Arabic RTL PDF and Excel exports: render_pdf, ExcelService, print frame. Trigger: PDF, Excel, export, WeasyPrint, A3. تقرير، كشف، شهادة، تصدير، طباعة"
التقارير الرسميّة PDF وExcel — SchoolOS
الغرض: أن يخرج كلُّ ملفٍّ رسميٍّ من مسارٍ واحد: بنّاءٌ في سجلّ التصدير، وقالبٌ على الإطار المطبوع المركزيّ، وخطٌّ مقروءٌ بحدود المالك، وسطرُ تدقيق — لا نسخةً محلّيّةً لكلّ قالب.
كلُّ ما هنا متحقَّقٌ على main في 2026-09-28؛ والتفاصيلُ في المراجع.
متى تُستعمل ومتى لا
- نعم: PDF أو Excel يُنزَّل أو يُطبع، قالبٌ ورقيّ، ترويسةٌ أو تذييل، مقاسُ ورق، حجمُ خطٍّ مطبوع، تحويلُ تصديرٍ متزامنٍ إلى خلفيّ.
- لا: صفحةُ ويبٍ تُعرض على الشاشة (ولا «زرَّ طباعة صفحة» — ممنوعٌ بحارس)، ولا قرارُ الخصوصيّة نفسُه.
الإجراء
- ابنِ البنّاءَ لا الـview: دالّةٌ نقيّةٌ
build(school, user, params) -> ExportResultتُسجَّل فيAppConfig.ready()بـcore.exports.registry.register(kind, build=…, capability=…)، والـview تناديrespond_export(request, kind). الافتراضُmode="job"(خلفيّ)، وdirectيرفضه السجلُّ بلا p95 مقيسٍ ≤ 1000ms. ←references/00-export-pipeline.md - القالبُ على الإطار المركزيّ: انسخ
assets/report_template.html(ترويسةٌ وتذييلٌ بوسومprint_frame، وعلامةُdata-pdf-own-page)، وعبّئ المحتوى وحدَه. ←references/10-print-frame.md - الخطُّ بحدود المالك (D2): قوائمُ وجداولُ متعدّدةُ الصفحات 10pt، متنُ النماذج 11–12pt وأدنى 10، العنوانُ 16 (أدنى 14)، التذييلُ 10 (أدنى 9). ما لا يسع يأخذ A3 أو صفحاتٍ أكثر — لا خطّاً أصغر.
- Excel بأدوات المنصّة:
ExcelServiceأوcore.export_utils(add_excel_title_rows،excel_table_styles)، ويخرج بـexcel_to_response/ExcelService.to_responseلتلحقه رؤيةُ الوزارة في ذيل الطباعة. ←references/20-excel.md - الخصوصيّة والتدقيق:
log_export(أوrows/full_national_idفيExportResult)، والرقمُ الشخصيّ مستورٌ في كلّ كشفٍ جماعيّ. ←references/30-content-and-privacy.mdومهارةpdppl-pii-audit. - تحقّق: صيّر PDF حقيقيّاً (WeasyPrint في حاوية الجلسة) وقس الصفحاتِ وأصغرَ خطّ، وشغّل
tests/test_print_frame_guard.pyوtests/test_export_guards.pyوtests/test_national_id_never_bulk.py. تشغيلُ الخادم والاختبارات في شجرة عملك بأوامرCLAUDE.md؛ وخطواتُ الفلو فيschoolos-flow.
القواعد وأسبابها
- لا
render_pdf/render_pdf_bytes/Workbookجديدٌ داخل view —HEAVY_IN_VIEWSفيtests/test_export_guards.pyسقّاطةٌ تنقص ولا تزيد. السبب: WeasyPrint وحدَه 400–550ms، وأبطأُ تصديرٍ كان 19.9ث يزاحم daphne الذي يخدم WebSocket (ADR-0007). - الإطارُ في مكوّنٍ واحد: لا
running(ولا@bottom-ولا أصنافُ*-footerفي قالب —tests/print_frame_ratchet.py(ملفٌّ جديدٌ رقمُه صفر). السبب: خمسُ نسخٍ متباينةٍ أخرجت تذييلاً بسطرين وخطّاً 6–8pt. data-pdf-own-pageإلزاميٌّ مع وسوم الإطار: بدونه يحقنcore/pdf_utils.pyإطارَه القديم (يغلب الترويسةَ المركزيّةَ أو يضيف «SchoolOS v6» والتاريخ في الزاويتين). مقيسٌ بتصيير WeasyPrint في 2026-09-28.- الرؤيةُ سطرٌ واحدٌ في كلّ تذييل (PDF وExcel)، ونصُّها من
components/ministry_vision.htmlلا حرفيّاً. السبب: أمرُ المالك 2026-09-27 (المواصفة v2.4، D1). - لا
@font-faceولا{% static %}للخطّ في قالب PDF:_inject_fontsيحقن Tajawal/Amiri/Noto Naskh بمساراتٍ مطلقة؛ والرابطُ النسبيّ يسقط صامتاً إلى DejaVu. وفي العامل لا manifest: مساراتُ الثابت بمسارٍ نسبيٍّ (for_pdf=True). - لا قصَّ للنصّ الحرّ في المطبوع (لا
line-clampولاtruncatechars) — رفضه المالك؛ والطويلُ يأخذ صفحةً أخرى. - الألوانُ
{% brand_color "…" %}لا سداسيّاً — حارسُ الهويّة يعدّ السداسيَّ في القوالب.
فخاخٌ حقيقيّة
- خطأ: نسخُ ترويسة
reports/base_qatar_report.htmlأو@page { @top-center … }إلى قالبٍ جديد. الصواب:{% print_frame_css %}+{% print_frame_header %}+{% print_frame_footer %}قبل المحتوى. - خطأ: «وزارة التعليم والتعليم العالي» و
assets/brand/qatar-emblem-2022.svg. الصواب: «وزارة التربية والتعليم والتعليم العالي — دولة قطر» (core/templatetags/print_frame.py::MINISTRY) نصّاً بلا صورةِ شعار — شعارُ الوزارة أُزيل من المنصّة كلِّها (D-386م)، والإطارُ يكتب السطرَ عنك. - خطأ: خطوط Noto Sans Arabic أو Cairo أو IBM Plex. الصواب: غيرُ موجودةٍ في
static/fonts/؛ المتاح Tajawal وAmiri وNoto Naskh Arabic (وTraditional Arabic منStoredFileإن ثُبّت). - خطأ: «≥ 9pt للبيانات يكفي». الصواب: D2: 10pt للقوائم والجداول؛ الاستثناءُ الوحيد الجدولُ العامّ 7.9pt بقرارٍ خاصّ.
- خطأ:
ws.oddFooter.center.text = "صفحة &P من &N"بعد البناء. الصواب:apply_print_footer(عبرexcel_to_response) يكتب الصفحةَ والرؤيةَ سطراً واحداً — والكتابةُ فوقه تُسقط الرؤية. - خطأ:
ws.freeze_panes = "A2"مع ترويسة المنصّة. الصواب: ثلاثةُ صفوف عنوانٍ ثمّ رأسُ الأعمدة في الصفّ 4، فالتجميدُ"A5"وتكرارُ الطباعة"1:4". - خطأ: «التاريخ الهجريّ بـ
hijri-converter» و«تصنيفُ السرّيّة في التذييل». الصواب: لا مكتبةَ هجريّةً فيrequirements.txtولا تصنيفَ سرّيّةٍ في الإطار؛ كلاهما يحتاج قرارَ المالك قبل أن يُكتب. - خطأ: جدولٌ فارغٌ يُمرَّر إلى المولّد. الصواب: حارسٌ قبل التوليد (رسالةٌ أو حالةٌ فارغة) — مسارُ xhtml2pdf الاحتياطيّ ينهار على الجدول الفارغ (
reports/views.py).
المراجع
| الملف | متى تقرأه |
|---|---|
references/00-export-pipeline.md |
قبل كتابة أيّ تصدير: السجلّ، البنّاء، الـview، العامل، الحرّاس |
references/10-print-frame.md |
حين تكتب قالب PDF أو تشتكي من ترويسةٍ أو تذييلٍ أو خطٍّ أو مقاس |
references/20-excel.md |
حين تبني ملفّ Excel أو تعدّل واحداً |
references/30-content-and-privacy.md |
لبنية المحتوى، والتوقيعات، والرقم الشخصيّ، واسم الملفّ، والحالات الحدّيّة |
references/99-test-cases.md |
لاختبار تفعيل المهارة وجودة جوابها |
assets/report_template.html |
نقطةُ بدايةٍ لقالب تقريرٍ جدوليٍّ جديد (مُختبَرٌ بتصييرٍ حقيقيّ) |