רישום ייבוא מוצרים עם דוחות והתראות

כאשר ייבוא מוצרים לילי מסתיים בשגיאות ומנהלים מבזבזים שעות בבוקר בחיפוש אחר הגורמים, העסק מפסיד זמן וכסף. אנו מפתחים מערכת רישום ייבוא המתעדת כל שלב ומייצרת דוחות ברורים עם התראות. הצוות שלנו מספק את הפרויקט במפתח מלא—מביקורת ועד הטמעה ותמיכה שוטפת, תוך הבטחת שקיפות ואמינות תהליכית.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
רישום ייבוא מוצרים עם דוחות והתראות
פשוט
מ- 1 יום עד 3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1331
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

תארו לעצמכם: ייבוא לילי של 50,000 מוצרים מ-1C. בבוקר, המנהל רואה שמחירים של 200 פריטים השתבשו. ללא לוגים — יום של חיפוש ידני. עם המערכת שלנו — 5 דקות לניתוח הדוח. לוג טוב לוכד כל שלב, והדוח נותן תשובה חד-משמעית: מה קרה, מה השתנה, מה נשבר.

אנו מיישמים מערכת לוגים לייבוא מוצרים במפתח מלא. הניסיון שלנו — מעל 50 פרויקטים באינטגרציה ותהליכי ETL לחנות מקוונת. נבחן את הפרויקט שלכם ונציע פתרון תוך יום אחד. המערכת תקצר את זמן איתור הבעיות ב-80% ותספק שקיפות מלאה לתהליך. הפסדים אופייניים משגיאות ייבוא בחנות עם 10,000 מוצרים מגיעים עד $900–1.3k בחודש — הפתרון שלנו ממזער אותם. במאמר זה נסביר כיצד להגדיר לוגים עם חציצה (buffering), מעקב שינויים והתראות.

כיצד פועלת מערכת הלוגים לייבוא

אילו נתונים יש לרשום בלוג במהלך הייבוא?

ברמת ריצת הייבוא:

  • זמני התחלה וסיום
  • מקור נתונים, סוג, כתובת URL/נתיב קובץ
  • מונה סופי: נוצר / עודכן / דולג / שגיאות
  • סטטוס: הצלחה / חלקי / נכשל
  • המשתמש שהפעיל את הייבוא (אם ידני)

ברמת שורה בודדת:

  • מספר שורה / SKU
  • סוג פעולה: יצירה / עדכון / דילוג / שגיאה
  • שדות שהשתנו (diff)
  • הודעת שגיאה (אם קיימת)

סכמת מסד נתונים ללוגים

CREATE TABLE import_runs (
  id serial PRIMARY KEY,
  source_id int REFERENCES import_sources(id),
  status varchar(20) DEFAULT 'pending', -- pending | processing | success | partial | failed
  trigger varchar(20) DEFAULT 'scheduled', -- scheduled | manual | webhook
  triggered_by int REFERENCES users(id),
  file_name varchar(500),
  file_size bigint,
  total_rows int DEFAULT 0,
  created_count int DEFAULT 0,
  updated_count int DEFAULT 0,
  skipped_count int DEFAULT 0,
  errors_count int DEFAULT 0,
  started_at timestamptz,
  completed_at timestamptz,
  duration_ms int,
  error_message text,
  created_at timestamptz DEFAULT now()
);
CREATE TABLE import_row_logs (
  id bigserial PRIMARY KEY,
  import_id int REFERENCES import_runs(id) ON DELETE CASCADE,
  line_number int,
  sku varchar(100),
  operation varchar(10), -- create | update | skip | error
  changed_fields jsonb, -- {"price": {"old": 100, "new": 120}}
  error_code varchar(50),
  error_msg text,
  created_at timestamptz DEFAULT now()
);
CREATE INDEX import_row_logs_import_id_idx ON import_row_logs (import_id);
CREATE INDEX import_row_logs_sku_idx ON import_row_logs (sku);

מימוש לוגר עם חציצה ו-diff

המחלקה הראשית CREATE TABLE import_runs ( id serial PRIMARY KEY, source_id int REFERENCES import_sources(id), status varchar(20) DEFAULT 'pending', -- pending | processing | success | partial | failed trigger varchar(20) DEFAULT 'scheduled', -- scheduled | manual | webhook triggered_by int REFERENCES users(id), file_name varchar(500), file_size bigint, total_rows int DEFAULT 0, created_count int DEFAULT 0, updated_count int DEFAULT 0, skipped_count int DEFAULT 0, errors_count int DEFAULT 0, started_at timestamptz, completed_at timestamptz, duration_ms int, error_message text, created_at timestamptz DEFAULT now() ); CREATE TABLE import_row_logs ( id bigserial PRIMARY KEY, import_id int REFERENCES import_runs(id) ON DELETE CASCADE, line_number int, sku varchar(100), operation varchar(10), -- create | update | skip | error changed_fields jsonb, -- {"price": {"old": 100, "new": 120}} error_code varchar(50), error_msg text, created_at timestamptz DEFAULT now() ); CREATE INDEX import_row_logs_import_id_idx ON import_row_logs (import_id); CREATE INDEX import_row_logs_sku_idx ON import_row_logs (sku); מנהלת כתיבת לוגים. חציצה של רשומות בקבוצות של 500 — במקום INSERT לכל שורה, מפחיתה את העומס על מסד הנתונים פי 10 בייבוא סטנדרטי.

class ImportLogger {
    private ImportRun $run;
    private array $rowBuffer = [];
    private int $bufferSize = 500;

    public function start(int $sourceId, string $trigger, ?int $userId): void
    {
        $this->run = ImportRun::create([
            'source_id' => $sourceId,
            'status' => 'processing',
            'trigger' => $trigger,
            'triggered_by' => $userId,
            'started_at' => now(),
        ]);
    }

    public function logRow(
        int $line,
        string $sku,
        string $operation,
        array $changedFields = [],
        ?string $errorMsg = null,
        ?string $errorCode = null
    ): void {
        $this->rowBuffer[] = [
            'import_id' => $this->run->id,
            'line_number' => $line,
            'sku' => $sku,
            'operation' => $operation,
            'changed_fields'=> $changedFields ? json_encode($changedFields) : null,
            'error_code' => $errorCode,
            'error_msg' => $errorMsg,
            'created_at' => now()->toDateTimeString(),
        ];

        if (count($this->rowBuffer) >= $this->bufferSize) {
            $this->flush();
        }
    }

    public function finish(string $status, ?string $errorMessage = null): void
    {
        $this->flush();

        $counts = DB::table('import_row_logs')
            ->where('import_id', $this->run->id)
            ->selectRaw("
                SUM(CASE WHEN operation = 'create' THEN 1 ELSE 0 END) AS created,
                SUM(CASE WHEN operation = 'update' THEN 1 ELSE 0 END) AS updated,
                SUM(CASE WHEN operation = 'skip' THEN 1 ELSE 0 END) AS skipped,
                SUM(CASE WHEN operation = 'error' THEN 1 ELSE 0 END) AS errors
            ")
            ->first();

        $this->run->update([
            'status' => $status,
            'created_count' => $counts->created,
            'updated_count' => $counts->updated,
            'skipped_count' => $counts->skipped,
            'errors_count' => $counts->errors,
            'completed_at' => now(),
            'duration_ms' => now()->diffInMilliseconds($this->run->started_at),
            'error_message' => $errorMessage,
        ]);
    }

    private function flush(): void
    {
        if (!empty($this->rowBuffer)) {
            DB::table('import_row_logs')->insert($this->rowBuffer);
            $this->rowBuffer = [];
        }
    }
}

מעקב שינויים (diff) עוקב אחר שדות ספציפיים: מחיר, מלאי, שם, תיאור. המתודה ImportLogger מחזירה מערך של שינויים, שנכתב ל-class ImportLogger { private ImportRun $run; private array $rowBuffer = []; private int $bufferSize = 500; public function start(int $sourceId, string $trigger, ?int $userId): void { $this->run = ImportRun::create([ 'source_id' => $sourceId, 'status' => 'processing', 'trigger' => $trigger, 'triggered_by' => $userId, 'started_at' => now(), ]); } public function logRow( int $line, string $sku, string $operation, array $changedFields = [], ?string $errorMsg = null, ?string $errorCode = null ): void { $this->rowBuffer[] = [ 'import_id' => $this->run->id, 'line_number' => $line, 'sku' => $sku, 'operation' => $operation, 'changed_fields'=> $changedFields ? json_encode($changedFields) : null, 'error_code' => $errorCode, 'error_msg' => $errorMsg, 'created_at' => now()->toDateTimeString(), ]; if (count($this->rowBuffer) >= $this->bufferSize) { $this->flush(); } } public function finish(string $status, ?string $errorMessage = null): void { $this->flush(); $counts = DB::table('import_row_logs') ->where('import_id', $this->run->id) ->selectRaw(" SUM(CASE WHEN operation = 'create' THEN 1 ELSE 0 END) AS created, SUM(CASE WHEN operation = 'update' THEN 1 ELSE 0 END) AS updated, SUM(CASE WHEN operation = 'skip' THEN 1 ELSE 0 END) AS skipped, SUM(CASE WHEN operation = 'error' THEN 1 ELSE 0 END) AS errors ") ->first(); $this->run->update([ 'status' => $status, 'created_count' => $counts->created, 'updated_count' => $counts->updated, 'skipped_count' => $counts->skipped, 'errors_count' => $counts->errors, 'completed_at' => now(), 'duration_ms' => now()->diffInMilliseconds($this->run->started_at), 'error_message' => $errorMessage, ]); } private function flush(): void { if (!empty($this->rowBuffer)) { DB::table('import_row_logs')->insert($this->rowBuffer); $this->rowBuffer = []; } } } .

private function buildDiff(Product $existing, array $newData): array
{
    $trackFields = ['price', 'qty', 'name', 'description'];
    $diff = [];

    foreach ($trackFields as $field) {
        $old = $existing->{$field};
        $new = $newData[$field] ?? null;

        if ((string) $old !== (string) $new) {
            $diff[$field] = ['old' => $old, 'new' => $new];
        }
    }

    return $diff;
}

למה חשוב לתעד diff?

ללא diff, לא תדעו מה השתנה במוצר: המחיר ירד ב-20% או שהתיאור התערבב. דוח מצטבר מראה כמה פריטים הושפעו בכל שדה. המנהל רואה מיד את היקף השינויים — זה מהיר פי עשרות מבדיקה ידנית. המערכת שלנו חוסכת עד 80% מזמן הניפוי, ששווה ערך ל-$360–520 בחודש.

דוחות והתראות

דוח מצטבר

המחלקה buildDiff מייצרת דוח עם 10 קודי השגיאה המובילים וספירת שינויים לפי שדה.

class ImportReportBuilder {
    public function build(ImportRun $run): ImportReport {
        $topErrors = DB::table('import_row_logs')
            ->where('import_id', $run->id)
            ->where('operation', 'error')
            ->select('error_code', DB::raw('COUNT(*) as count'), DB::raw('MIN(sku) as example_sku'))
            ->groupBy('error_code')
            ->orderByDesc('count')
            ->limit(10)
            ->get();

        $priceChanges = DB::table('import_row_logs')
            ->where('import_id', $run->id)
            ->where('operation', 'update')
            ->whereRaw("changed_fields ? 'price'")
            ->count();

        return new ImportReport(
            run: $run,
            topErrors: $topErrors,
            priceChangesCount: $priceChanges,
        );
    }
}

התראות על תוצאות

ההתראה נשלחת רק אם הסטטוס אינו changed_fields או שמספר השגיאות עובר סף מסוים. האימייל מכיל סיכום וקישור לדוח.

class ImportCompletedNotification extends Notification
{
    public function toMail(mixed $notifiable): MailMessage
    {
        $run = $this->run;

        return (new MailMessage)
            ->subject("Импорт #{$run->id}: {$run->status}")
            ->line("Источник: {$run->source->name}")
            ->line("Создано: {$run->created_count}, обновлено: {$run->updated_count}, ошибок: {$run->errors_count}")
            ->line("Длительность: " . round($run->duration_ms / 1000, 1) . " сек")
            ->when($run->errors_count > 0, fn($m) => $m->action('Просмотреть ошибки', $this->reportUrl()));
    }
}

איך התראות עוזרות למנוע משבר?

ההתראה מגיעה באימייל רק על ייבוא חלקי או נכשל. האימייל מכיל סיכום: נוצר, עודכן, שגיאות, משך זמן. אם אין שגיאות, המנהל לא מוסח. אם יש שגיאות, הם עוברים לדוח ורואים 10 קודי השגיאה המובילים עם דוגמאות SKU.

סיבוב לוגים

לוגים ברמת שורה גדלים במהירות. מדיניות שמירה: מחיקת פרטי ייבוא מוצלח ישן פעם בחודש. רשומות סיכום של import_run נשמרות לצמיתות — הן תופסות מעט מקום. פקודת Artisan private function buildDiff(Product $existing, array $newData): array { $trackFields = ['price', 'qty', 'name', 'description']; $diff = []; foreach ($trackFields as $field) { $old = $existing->{$field}; $new = $newData[$field] ?? null; if ((string) $old !== (string) $new) { $diff[$field] = ['old' => $old, 'new' => $new]; } } return $diff; } רצה שבועית לפי לוח זמנים.

השוואת גישות לרישום לוגים

גישה ביצועים פירוט ביקורת
רישום שורות פשוט גבוה נמוך (ללא צבירה) ללא diff
רישום עם חציצה ו-diff גבוה (חציצה של 500 שורות) גבוה (כל שורה, diff) מספיק לחנות
טבלת שינויים היסטורית מלאה נמוך (ללא חלוקה) מלא מלא אך יקר

אנו בוחרים בגישה עם חציצה — היא לא מעמיסה על מסד הנתונים ומספקת תמונה מפורטת לכל שורה.

מה כלול בעבודה

  1. עיצוב סכמת מסד נתונים המותאמת לקטלוג שלכם ולתדירות הייבוא
  2. מימוש לוגר עם חציצה, diff ודוח
  3. הגדרת התראות (אימייל, טלגרם לפי בקשה)
  4. ממשק צפייה בלוגים בפאנל הניהול (טבלה עם סינון לפי ייבוא, סטטוס, SKU)
  5. סיבוב לוגים ישנים (פקודת Artisan, תקופת שמירה ניתנת להגדרה)
  6. תיעוד API ומדריך למנהל
  7. אחריות על קוד — 6 חודשים

לוח זמנים לביצוע

שלב משך
ImportLogger עם חציצה, טבלאות DB, מוני סיום יום אחד
diff שדות, דוח מצטבר, התראות 0.5 יום
ממשק צפייה בלוגים בפאנל הניהול, סיבוב רשומות ישנות 0.5 יום

Logging — גישה סטנדרטית למעקב אחר אירועים במערכות IT.

צרו קשר לייעוץ. הזמינו היום את מימוש מערכת הלוגים לייבוא. קבלו שקיפות מלאה בייבוא והפחתת הפסדים.