فصل ۸: خودکارسازی و پروژه‌ی پایانی

پروژه‌ی پایانی ۱: داشبورد فروش کارخانه‌ی فرش کاشان — از CSV خام تا مدل داده

سناریوی پروژه

یک کارخانه‌ی فرش ماشینی در کاشان دوازده نماینده‌ی فروش در استان‌های مختلف دارد. نرم‌افزار حسابداری هر ماه یک فایل CSV از فاکتورها می‌دهد و مدیرعامل هر شنبه می‌پرسد: «این ماه چقدر فروختیم، کدام طرح و کدام استان، و نسبت به ماه قبل چطور؟». هدف: فایلی که هر ماه فقط با انداختن CSV جدید در پوشه و یک Refresh All به‌روز شود. این پروژه فصل‌های ۱ تا ۷ را به هم وصل می‌کند.

ورودی‌ها

فایل یا جدولستون‌هامنبع
Sales\1403-01.csv و …Date, InvoiceNo, Customer, Rep, Design, Reed, Area, Amountخروجی ماهانه‌ی حسابداری
Products.xlsxDesign, Collection, Density, ListPriceواحد تولید
جدول RepsRep, Province, Managerواحد فروش، در همین فایل
جدول CalMiladi, Shamsi, Year, Month, MonthName, YM, MonthIdxجدول تقویم فصل ۱

گام ۱: Power Query

  1. Query Sales: From Folder روی پوشه‌ی Sales با کد M فصل ۵ (Encoding 65001، اصلاح ی و ک، تعیین نوع داده با Culture).
  2. Query Products و Reps: ستون‌های کلید (Design و Rep) را Trim و اصلاح حروف کنید؛ «طرح افشان» با ی عربی در یک طرف و ی فارسی در طرف دیگر، رابطه را بی‌صدا می‌شکند.
  3. کنترل کیفیت: یک Query با Merge از نوع Left Anti بین Sales و Products بسازید که طرح‌های ناشناخته را نشان دهد. این Query باید همیشه خالی باشد.
  4. همه را با Close & Load To ← Only Create Connection و تیک Add this data to the Data Model بارگذاری کنید.
// Query: Sales_Missing_Design  (باید صفر سطر داشته باشد)
let
    J = Table.NestedJoin(Sales, {"Design"}, Products, {"Design"}, "P", JoinKind.LeftAnti),
    R = Table.Distinct(Table.SelectColumns(J, {"Design"}))
in
    R

گام ۲: رابطه‌ها و Measureها

Data ← Relationships (یا Power Pivot ← Diagram View): Sales[Date] → Cal[Miladi]، Sales[Design] → Products[Design] و Sales[Rep] → Reps[Rep]. جدول فروش در مرکز و جدول‌های بُعد دورش؛ همان «مدل ستاره‌ای» که هر ابزار BI انتظارش را دارد.

Sales Amount   := SUM ( Sales[Amount] )
Area m2        := SUM ( Sales[Area] )
Price per m2   := DIVIDE ( [Sales Amount], [Area m2] )
Customers      := DISTINCTCOUNT ( Sales[Customer] )
Invoices       := DISTINCTCOUNT ( Sales[InvoiceNo] )

-- ماه قبلِ شمسی با MonthIdx (توابع Time Intelligence میلادی‌اند)
Prev Month Sales :=
VAR cur = MAX ( Cal[MonthIdx] )
RETURN CALCULATE ( [Sales Amount], ALL ( Cal ), Cal[MonthIdx] = cur - 1 )

MoM %          := DIVIDE ( [Sales Amount] - [Prev Month Sales], [Prev Month Sales] )

ستون MonthIdx در جدول تقویم برابر Year*12+Month است؛ عددی پیوسته که می‌داند ماه قبلِ فروردین ۱۴۰۴، اسفند ۱۴۰۳ است. توابعی مثل PREVIOUSMONTH و SAMEPERIODLASTYEAR بر اساس ماه میلادی کار می‌کنند و در گزارش شمسی عدد غلط اما «معقول‌نما» می‌دهند؛ خطرناک‌ترین نوع خطا.

گام ۳: Pivotهای محاسبه

در شیت Calc از Data Model سه Pivot بسازید: (۱) YM در سطرها با Sales Amount و Price per m2؛ (۲) Province با Sales Amount؛ (۳) Design با Value Filters ← Top 10. چیدمان را Tabular کنید و سرستون‌ها را کوتاه. کارت‌ها را در درس بعد مستقیم از مدل با CUBEVALUE می‌سازیم.

نکته‌هایی که کمتر کسی می‌داند

  • نام Queryها، جدول‌ها و ستون‌های مدل را لاتین و بدون فاصله بگذارید؛ DAX با نام فارسی هم کار می‌کند، اما فرمولی که نیمی RTL و نیمی LTR است در نوار فرمول تقریباً ناخواناست.
  • در Power Pivot ستون MonthName را با Sort by Column بر اساس Month مرتب کنید؛ وگرنه ماه‌های فارسی در Pivot الفبایی چیده می‌شوند (آبان، آذر، اردیبهشت…).
  • اگر رابطه ساخته نمی‌شود و پیام many-to-many می‌آید، جدول بُعد کلید تکراری دارد. پیش از Remove Duplicates بفهمید چرا تکراری است؛ معمولاً یک طرح با دو قیمت ثبت شده است.
  • Queryهای میانی را Only Create Connection نگه دارید؛ بارگذاری هر Query در شیت حجم فایل و زمان Refresh را بی‌دلیل بالا می‌برد.
  • مسیر پوشه را در یک سلول نام‌دار (pPath) بگذارید و در M با Excel.CurrentWorkbook(){[Name="pPath"]}[Content]{0}[Column1] بخوانید؛ با جابه‌جایی پوشه یا تحویل فایل به همکار، فقط یک سلول عوض می‌شود.

برای ذخیره‌ی پیشرفت و شرکت در آزمون، وارد شوید — رایگان است.