PHPackages                             officeguy/laravel-sumit-gateway - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. officeguy/laravel-sumit-gateway

ActiveLibrary[Payment Processing](/categories/payments)

officeguy/laravel-sumit-gateway
===============================

Laravel package for SUMIT payment gateway (core) - 1:1 port from WooCommerce (Laravel 12/13 Compatible)

v3.0.3(3mo ago)0249[7 PRs](https://github.com/nm-digitalhub/SUMIT-Payment-Gateway-for-laravel/pulls)1MITPHPPHP ^8.2

Since Nov 20Pushed 2mo agoCompare

[ Source](https://github.com/nm-digitalhub/SUMIT-Payment-Gateway-for-laravel)[ Packagist](https://packagist.org/packages/officeguy/laravel-sumit-gateway)[ RSS](/packages/officeguy-laravel-sumit-gateway/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (18)Versions (127)Used By (1)

SUMIT (OfficeGuy) Payment Gateway for Laravel 12/13
===================================================

[](#sumit-officeguy-payment-gateway-for-laravel-1213)

**Clone 1:1 של התוסף WooCommerce `woo-payment-gateway-officeguy` עבור Laravel.**

תמיכה רשמית:

- Laravel 12
- Laravel 13
- PHP 8.2+ עבור Laravel 12
- PHP 8.3+ עבור Laravel 13
- תשלומים בכרטיס אשראי (PCI modes: no/redirect/yes)
- תשלומי Bit
- תמיכה ב‑Tokens (J2/J5), Authorize Only, תשלומים (עד 36), recurring
- מסמכים (חשבונית/קבלה/תרומה), שילוב PayPal/BlueSnap receipts
- Multivendor &amp; CartFlows מקבילים (לפי מפרט המקור)
- סנכרון מלאי (12/24 שעות/Checkout), ווידג'ט דשבורד (למימוש עתידי)
- ממשק ניהול Filament v4
- דפי לקוח Filament להצגת טרנזקציות/מסמכים/אמצעי תשלום

עדכון סנכרון (2025-12-15)
-------------------------

[](#עדכון-סנכרון-2025-12-15)

- כל קבצי OfficeGuy (views/partials/filament) סונכרנו מהמערכת הראשית (`httpdocs/vendor/officeguy/laravel-sumit-gateway`).
- נוספה `resources/css/checkout-mobile.css` (מותאם ברנד) לחבילה; במקור לא היה CSS צ'קאאוט.
- `success-card.blade.php` הוחלף לגרסה שמבוססת על שדות token גולמיים (`card_type`, `last_four`, `exp_month/exp_year`).

תוכן עניינים
------------

[](#תוכן-עניינים)

- [התקנה](#%D7%94%D7%AA%D7%A7%D7%A0%D7%94)
- [הגדרות](#%D7%94%D7%92%D7%93%D7%A8%D7%95%D7%AA)
- [עמוד תשלום](#%D7%A2%D7%9E%D7%95%D7%93-%D7%AA%D7%A9%D7%9C%D7%95%D7%9D)
- [שדות ת"ז ו-CVV](#%D7%A9%D7%93%D7%95%D7%AA-%D7%AA%D7%96-%D7%95-cvv)
- [מסמכים](#%D7%9E%D7%A1%D7%9E%D7%9B%D7%99%D7%9D)
- [סוגי תשלומים](#%D7%A1%D7%95%D7%92%D7%99-%D7%AA%D7%A9%D7%9C%D7%95%D7%9E%D7%99%D7%9D)
- [תשלומים מחולקים](#%D7%AA%D7%A9%D7%9C%D7%95%D7%9E%D7%99%D7%9D-%D7%9E%D7%97%D7%95%D7%9C%D7%A7%D7%99%D7%9D-installments)
- [תפיסת מסגרת (Authorize Only)](#%D7%AA%D7%A4%D7%99%D7%A1%D7%AA-%D7%9E%D7%A1%D7%92%D7%A8%D7%AA-authorize-only)
- [מצב טסט](#%D7%9E%D7%A6%D7%91-%D7%98%D7%A1%D7%98)
- [שמירת פרטי אשראי](#%D7%A9%D7%9E%D7%99%D7%A8%D7%AA-%D7%A4%D7%A8%D7%98%D7%99-%D7%90%D7%A9%D7%A8%D7%90%D7%99-tokens)
- [הוראות קבע ומנויים](#%D7%94%D7%95%D7%A8%D7%90%D7%95%D7%AA-%D7%A7%D7%91%D7%A2-%D7%95%D7%9E%D7%A0%D7%95%D7%99%D7%99%D7%9D-subscriptions)
- [מלאי](#%D7%9E%D7%9C%D7%90%D7%99-stock-management)
- [Bit ו-Redirect](#bit-%D7%95-redirect)
- [מיזוג לקוחות](#%D7%9E%D7%99%D7%96%D7%95%D7%92-%D7%9C%D7%A7%D7%95%D7%97%D7%95%D7%AA-%D7%90%D7%95%D7%98%D7%95%D7%9E%D7%98%D7%99)
- [Multi-Vendor](#multi-vendor)
- [תרומות](#%D7%AA%D7%A8%D7%95%D7%9E%D7%95%D7%AA-donations)
- [Upsell / CartFlows](#upsell--cartflows)
- [יצירת משתמש אוטומטית לאחר תשלום](#%D7%99%D7%A6%D7%99%D7%A8%D7%AA-%D7%9E%D7%A9%D7%AA%D7%9E%D7%A9-%D7%90%D7%95%D7%98%D7%95%D7%9E%D7%98%D7%99%D7%AA-%D7%9C%D7%90%D7%97%D7%A8-%D7%AA%D7%A9%D7%9C%D7%95%D7%9D-v1140)
- [Secure Success Page - עמוד הצלחה מאובטח](#secure-success-page---%D7%A2%D7%9E%D7%95%D7%93-%D7%94%D7%A6%D7%9C%D7%97%D7%94-%D7%9E%D7%90%D7%95%D7%91%D7%98%D7%97-v120)
- [אירועים](#%D7%90%D7%99%D7%A8%D7%95%D7%A2%D7%99%D7%9D-events)
- [Custom Event Webhooks](#custom-event-webhooks)
- [Webhook Events Resource](#webhook-events-resource-admin-panel)
- [קבלת Webhooks מ-SUMIT](#%D7%A7%D7%91%D7%9C%D7%AA-webhooks-%D7%9E-sumit-incoming-webhooks)
- [מיגרציות נתונים](#%D7%9E%D7%99%D7%92%D7%A8%D7%A6%D7%99%D7%95%D7%AA-%D7%A0%D7%AA%D7%95%D7%A0%D7%99%D7%9D)
- [בדיקות](#%D7%91%D7%93%D7%99%D7%A7%D7%95%D7%AA)
- [קבצים לפרסום](#%D7%A7%D7%91%D7%A6%D7%99%D7%9D-%D7%9C%D7%A4%D7%A8%D7%A1%D7%95%D7%9D-publishable-assets)

התקנה
-----

[](#התקנה)

```
composer require officeguy/laravel-sumit-gateway
php artisan migrate   # יריץ את כל מיגרציות החבילה
```

> Laravel 13 דורש PHP 8.3 ומעלה. אם האפליקציה שלכם עדיין על PHP 8.2, הישארו עם Laravel 12.

> אם תרצה להעתיק גם קונפיג/מיגרציות/תצוגות: `--tag=officeguy-config`, `--tag=officeguy-migrations`, `--tag=officeguy-views`. ראה [קבצים לפרסום](#%D7%A7%D7%91%D7%A6%D7%99%D7%9D-%D7%9C%D7%A4%D7%A8%D7%A1%D7%95%D7%9D-publishable-assets) לפרטים נוספים.

הגדרות
------

[](#הגדרות)

כל ההגדרות נשמרות במסד הנתונים (טבלת `officeguy_settings`) עם fallback לקובץ config. ניתן לערוך דרך Filament (עמוד **Gateway Settings**) או בקוד באמצעות `SettingsService`.

### גישה לעמוד ההגדרות

[](#גישה-לעמוד-ההגדרות)

נווטו ל-**SUMIT Gateway** &gt; **Gateway Settings** ב-Admin Panel.

### שדות עיקריים

[](#שדות-עיקריים)

- מפתחות חברה: company\_id, private\_key, public\_key
- PCI mode: `no` (PaymentsJS), `redirect`, `yes` (PCI server)
- תשלומים: max\_payments, min\_amount\_for\_payments, min\_amount\_per\_payment
- Authorize Only: דגל + אחוז תוספת + מינימום תוספת
- מסמכים: draft\_document, email\_document, create\_order\_document, merge\_customers, automatic\_languages
- Tokens: support\_tokens, token\_param (J2/J5)
- Bit: bit\_enabled
- מלאי: stock\_sync\_freq (none/12/24), checkout\_stock\_sync
- לוגים: logging, log\_channel, ssl\_verify
- מסלולי Redirect: routes.success, routes.failed
- Order binding: order.model או order.resolver (callable)

### התאמת נתיבים (Route Configuration)

[](#התאמת-נתיבים-route-configuration)

ניתן להתאים את כל נתיבי החבילה ישירות מה-Admin Panel:

**ב-Admin Panel:**נווטו ל-**SUMIT Gateway** &gt; **Gateway Settings** &gt; **Route Configuration**

**נתיבים ניתנים להתאמה:**

הגדרהברירת מחדלתיאורRoute Prefix`officeguy`קידומת לכל הנתיביםCard Callback`callback/card`חזרה מתשלום בכרטיסBit Webhook`webhook/bit`קבלת IPN מ-BitSUMIT Webhook`webhook/sumit`קבלת webhooks מ-SUMITDocument Download`documents/{document}`הורדת מסמכיםCheckout Charge`checkout/charge`חיוב ישירPublic Checkout`checkout/{id}`עמוד תשלום ציבוריSuccess Route`checkout.success`נתיב הצלחהFailed Route`checkout.failed`נתיב כישלון**דוגמה - שינוי נתיבים:**

1. גשו ל-Admin Panel &gt; Gateway Settings &gt; Route Configuration
2. שנו את Route Prefix ל-`payments`
3. שנו את Card Callback ל-`return/card`
4. שמרו את ההגדרות
5. נקו cache: `php artisan route:clear`

**תוצאה:**

- `POST /payments/return/card` במקום `POST /officeguy/callback/card`
- `POST /payments/webhook/bit` במקום `POST /officeguy/webhook/bit`

**או ב-.env:**

```
OFFICEGUY_ROUTE_PREFIX=payments
OFFICEGUY_CARD_CALLBACK_PATH=return/card
OFFICEGUY_BIT_WEBHOOK_PATH=ipn/bit
OFFICEGUY_SUMIT_WEBHOOK_PATH=triggers/sumit
```

**שימוש בקוד:**

```
use OfficeGuy\LaravelSumitGateway\Support\RouteConfig;

// קבלת כל הנתיבים המוגדרים
$paths = RouteConfig::getAllPaths();
// [
//     'prefix' => 'officeguy',
//     'card_callback' => 'officeguy/callback/card',
//     'bit_webhook' => 'officeguy/webhook/bit',
//     'sumit_webhook' => 'officeguy/webhook/sumit',
//     ...
// ]

// קבלת נתיב ספציפי
$cardCallbackPath = RouteConfig::getPrefix() . '/' . RouteConfig::getCardCallbackPath();
```

---

עמוד תשלום
----------

[](#עמוד-תשלום)

### תצוגה, ממשק ותוכן

[](#תצוגה-ממשק-ותוכן)

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

**הפעלה:**

```
// ב-Admin Panel
// נווטו ל-SUMIT Gateway > Gateway Settings > Public Checkout Page
// הפעילו את "Enable Public Checkout"
```

**או ב-.env:**

```
OFFICEGUY_ENABLE_PUBLIC_CHECKOUT=true
```

**גישה לעמוד:**

```
GET /officeguy/checkout/{id}

```

**יצירת קישור תשלום:**

```
$checkoutUrl = route('officeguy.public.checkout', ['id' => $order->id]);

// שליחה ללקוח
Mail::to($customer->email)->send(new PaymentLinkEmail($checkoutUrl));
```

### התאמת עיצוב עמוד התשלום

[](#התאמת-עיצוב-עמוד-התשלום)

```
php artisan vendor:publish --tag=officeguy-views
```

לאחר מכן ערכו את הקובץ: `resources/views/vendor/officeguy/pages/checkout.blade.php`

**תכונות עמוד התשלום:**

- תמיכה מלאה ב-RTL (עברית/ערבית)
- עיצוב רספונסיבי עם Tailwind CSS
- בחירת אמצעי תשלום (כרטיס אשראי / Bit)
- תמיכה בכרטיסים שמורים (טוקנים)
- בחירת מספר תשלומים
- סיכום הזמנה

---

שדות ת"ז ו-CVV
--------------

[](#שדות-תז-ו-cvv)

### הגדרת שדות חובה

[](#הגדרת-שדות-חובה)

ניתן להגדיר אם שדות ת.ז ו-CVV יהיו חובה, אופציונליים, או מוסתרים.

**ב-Admin Panel:**נווטו ל-**SUMIT Gateway** &gt; **Gateway Settings** &gt; **Payment Settings**

**אפשרויות לכל שדה:**

- `required` - חובה (ברירת מחדל)
- `yes` - אופציונלי (מוצג אך לא חובה)
- `no` - מוסתר

**ב-.env:**

```
OFFICEGUY_CITIZEN_ID=required   # required/yes/no
OFFICEGUY_CVV=required          # required/yes/no
```

**בקוד:**

```
// קריאה להגדרות
$settings = app(SettingsService::class);
$citizenIdMode = $settings->get('citizen_id', 'required');
$cvvMode = $settings->get('cvv', 'required');
```

> ⚠️ **חשוב:** חברות האשראי מחייבות הזנת נתונים אלה. כדי להסתיר את השדות, יש לקבל מהן פטור מהזנת מס' ת.ז ו-CVV.

---

מסמכים
------

[](#מסמכים)

### בחירת שפה אוטומטית

[](#בחירת-שפה-אוטומטית)

בברירת המחדל יופקו המסמכים בעברית. הפעלת "בחירת שפה אוטומטית" תאפשר להפיק את המסמכים בהתאם לשפת הלקוח/ה.

**ב-Admin Panel:**

- נווטו ל-**Gateway Settings** &gt; **Document Settings**
- סמנו את **"Automatic Languages"**

**ב-.env:**

```
OFFICEGUY_AUTOMATIC_LANGUAGES=true
```

### הפקת מסמך הזמנה

[](#הפקת-מסמך-הזמנה)

הפקת מסמך הזמנה נוסף ושליחתו ללקוח לאחר חיוב מוצלח, בנוסף למסמך חשבונית/קבלה.

**ב-Admin Panel:**

- סמנו את **"Create Order Document"**

**ב-.env:**

```
OFFICEGUY_CREATE_ORDER_DOCUMENT=true
```

### הגדרות מסמכים נוספות

[](#הגדרות-מסמכים-נוספות)

```
# שליחת מסמך במייל ללקוח
OFFICEGUY_EMAIL_DOCUMENT=true

# יצירת מסמך כטיוטא (לא סופי)
OFFICEGUY_DRAFT_DOCUMENT=false
```

### שיעור מע"מ מותאם

[](#שיעור-מעמ-מותאם)

```
// במודל Payable שלכם
public function getVatRate(): ?float
{
    return 17.0; // 17% מע"מ
}

public function isTaxEnabled(): bool
{
    return true;
}
```

---

סוגי תשלומים
------------

[](#סוגי-תשלומים)

### אינטגרציות עם PayPal ו-BlueSnap

[](#אינטגרציות-עם-paypal-ו-bluesnap)

הפקת מסמך (חשבונית/קבלה) אוטומטית בתשלום ב-PayPal, BlueSnap, או שערי תשלום אחרים.

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Additional Features**

**ב-.env:**

```
# PayPal - אפשרויות: no, yes, async
OFFICEGUY_PAYPAL_RECEIPTS=yes

# BlueSnap
OFFICEGUY_BLUESNAP_RECEIPTS=true

# שערים אחרים
OFFICEGUY_OTHER_RECEIPTS=stripe,paddle
```

**בקוד:**

```
// הפקת קבלה ידנית לתשלום PayPal
DocumentService::createReceiptForExternalPayment($order, 'paypal', $transactionId);
```

---

תשלומים מחולקים (Installments)
------------------------------

[](#תשלומים-מחולקים-installments)

### הגדרת עסקאות תשלומים

[](#הגדרת-עסקאות-תשלומים)

הגדרת מספר תשלומים (עד 36) אפשרי לעסקה.

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Payment Settings**

**הגדרות:**

- **Max Payments** - מספר תשלומים מקסימלי (עד 36)
- **Min Amount for Payments** - סכום מינימלי לאפשר תשלומים
- **Min Amount per Payment** - סכום מינימלי לתשלום בודד

**ב-.env:**

```
OFFICEGUY_MAX_PAYMENTS=12
OFFICEGUY_MIN_AMOUNT_FOR_PAYMENTS=100
OFFICEGUY_MIN_AMOUNT_PER_PAYMENT=50
```

**בקוד:**

```
// קבלת מספר תשלומים מקסימלי לסכום מסוים
$maxPayments = PaymentService::getMaximumPayments($amount);

// חיוב עם תשלומים
$result = PaymentService::processCharge($order, $paymentsCount = 6);
```

---

תפיסת מסגרת (Authorize Only)
----------------------------

[](#תפיסת-מסגרת-authorize-only)

### קביעת מסגרת אשראי לחיוב מושהה

[](#קביעת-מסגרת-אשראי-לחיוב-מושהה)

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

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Payment Settings**

**הגדרות:**

- **Authorize Only** - הפעלת מצב תפיסת מסגרת
- **Authorize Added Percent** - אחוז תוספת למסגרת (למשל: 20%)
- **Authorize Minimum Addition** - סכום תוספת מינימלי

**ב-.env:**

```
OFFICEGUY_AUTHORIZE_ONLY=true
OFFICEGUY_AUTHORIZE_ADDED_PERCENT=20
OFFICEGUY_AUTHORIZE_MINIMUM_ADDITION=50
```

**בקוד:**

```
// תפיסת מסגרת
$result = PaymentService::authorizePayment($order, $amount);

// חיוב מאוחר יותר
$result = PaymentService::capturePayment($transactionId, $finalAmount);
```

> 💡 **שימוש נפוץ:** בתי מלון, השכרת רכב, או כל עסקה שבה הסכום הסופי עשוי להשתנות.

---

מצב טסט
-------

[](#מצב-טסט)

### בדיקות ללא חיוב אמיתי

[](#בדיקות-ללא-חיוב-אמיתי)

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

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Environment Settings** &gt; סמנו **"Testing Mode"**

**ב-.env:**

```
OFFICEGUY_TESTING=true
```

**מספרי כרטיסים לבדיקות:**

כרטיסמספרתוקףCVVויזה (הצלחה)4580 0000 0000 0000כל תאריך עתידי123ויזה (כישלון)4580 0000 0000 0001כל תאריך עתידי123מאסטרקארד5326 1000 0000 0000כל תאריך עתידי123**בקוד:**

```
// בדיקה אם במצב טסט
$isTest = app(SettingsService::class)->get('testing', false);
```

> ⚠️ **חשוב:** לפני שהאתר עולה לאוויר, ודאו שביטלתם את מצב הטסט כדי לא לפספס מכירות אמיתיות!

---

שמירת פרטי אשראי (Tokens)
-------------------------

[](#שמירת-פרטי-אשראי-tokens)

### שמירת כרטיסי אשראי לרכישות חוזרות

[](#שמירת-כרטיסי-אשראי-לרכישות-חוזרות)

מאפשר ללקוחות לשמור את פרטי כרטיס האשראי לרכישות עתידיות מהירות יותר.

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Tokenization** &gt; סמנו **"Support Tokens"**

**ב-.env:**

```
OFFICEGUY_SUPPORT_TOKENS=true
OFFICEGUY_TOKEN_PARAM=5   # 5=J5 (מומלץ), 2=J2
```

**בקוד:**

```
// שמירת טוקן לאחר חיוב
$token = OfficeGuyToken::createFromApiResponse($customer, $response);

// חיוב עם טוקן שמור
$result = PaymentService::processCharge($order, $payments, false, false, $token);

// קבלת טוקנים של לקוח
$tokens = OfficeGuyToken::where('owner_type', get_class($user))
    ->where('owner_id', $user->id)
    ->get();
```

**תכונות:**

- שמירת פרטי כרטיס מאובטחת (PCI DSS)
- מילוי אוטומטי ברכישות הבאות
- תמיכה בחיובים חוזרים (Subscriptions)
- ניהול כרטיסים בפאנל לקוח

---

הוראות קבע ומנויים (Subscriptions)
----------------------------------

[](#הוראות-קבע-ומנויים-subscriptions)

### גביית תשלומים קבועים באשראי

[](#גביית-תשלומים-קבועים-באשראי)

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

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Subscriptions**

**הגדרות:**

- **Enable Subscriptions** - הפעלת מנויים
- **Default Interval (Months)** - מרווח ברירת מחדל בחודשים
- **Default Cycles** - מספר חיובים (ריק = ללא הגבלה)
- **Allow Pause** - אפשרות להשהות מנוי
- **Retry Failed Charges** - ניסיון חוזר בכישלון
- **Max Retry Attempts** - מספר ניסיונות מקסימלי

**ב-.env:**

```
OFFICEGUY_SUBSCRIPTIONS_ENABLED=true
OFFICEGUY_SUBSCRIPTIONS_DEFAULT_INTERVAL=1
OFFICEGUY_SUBSCRIPTIONS_DEFAULT_CYCLES=12
OFFICEGUY_SUBSCRIPTIONS_ALLOW_PAUSE=true
OFFICEGUY_SUBSCRIPTIONS_RETRY_FAILED=true
OFFICEGUY_SUBSCRIPTIONS_MAX_RETRIES=3
```

**יצירת מנוי:**

```
use OfficeGuy\LaravelSumitGateway\Services\SubscriptionService;

// יצירת מנוי חדש
$subscription = SubscriptionService::create(
    $user,              // הלקוח
    'תוכנית חודשית',    // שם המנוי
    99.00,              // סכום
    'ILS',              // מטבע
    1,                  // אינטרוול בחודשים
    12,                 // מספר חיובים (null = ללא הגבלה)
    $tokenId            // טוקן לתשלום
);

// חיוב ראשוני
$result = SubscriptionService::processInitialCharge($subscription);

// חיוב ידני
$result = SubscriptionService::processRecurringCharge($subscription);

// השהיית מנוי
SubscriptionService::pause($subscription);

// חידוש מנוי
SubscriptionService::resume($subscription);

// ביטול מנוי
SubscriptionService::cancel($subscription);
```

**תזמון חיובים חוזרים אוטומטיים:**

הוסיפו ל-`routes/console.php`:

```
use Illuminate\Support\Facades\Schedule;

// חיוב יומי בשעה 8:00
Schedule::command('sumit:process-recurring-payments')->dailyAt('08:00');

// או חיוב כל שעה
Schedule::command('sumit:process-recurring-payments')->hourly();

// עם דיווח על כשלונות
Schedule::command('sumit:process-recurring-payments')
    ->daily()
    ->emailOutputOnFailure('admin@example.com');
```

**הרצה ידנית:**

```
# הרצה אסינכרונית (כ-job)
php artisan sumit:process-recurring-payments

# הרצה סינכרונית
php artisan sumit:process-recurring-payments --sync

# עיבוד מנוי ספציפי
php artisan sumit:process-recurring-payments --subscription=123
```

---

מלאי (Stock Management)
-----------------------

[](#מלאי-stock-management)

### סנכרון מלאי עם מערכת החשבונות

[](#סנכרון-מלאי-עם-מערכת-החשבונות)

> 📦 **לניהול המלאי, יש להתקין את מודול מלאי בחשבון SUMIT.**

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Additional Features**

**הגדרות:**

- **Stock Sync Frequency** - תדירות סנכרון: `none`, `12` (שעות), `24` (שעות)
- **Checkout Stock Sync** - סנכרון בזמן Checkout

**ב-.env:**

```
OFFICEGUY_STOCK_SYNC_FREQ=12      # none/12/24
OFFICEGUY_CHECKOUT_STOCK_SYNC=true
```

**Callback לעדכון מלאי:**

```
// config/officeguy.php
'stock' => [
    'update_callback' => function(array $stockItem) {
        // עדכון מלאי במוצר
        $product = Product::where('sku', $stockItem['sku'])->first();
        if ($product) {
            $product->update(['stock_quantity' => $stockItem['quantity']]);
        }
    },
],
```

**הרצת סנכרון ידנית:**

```
php artisan sumit:stock-sync
```

**סנכרון בקוד:**

```
use OfficeGuy\LaravelSumitGateway\Services\Stock\StockSyncService;

// סנכרון כל המלאי
StockSyncService::syncAll();

// סנכרון מוצר ספציפי
StockSyncService::syncProduct($sku);
```

**תזמון סנכרון אוטומטי:**

```
// routes/console.php
Schedule::command('sumit:stock-sync')->everyTwelveHours();
```

---

Bit ו-Redirect
--------------

[](#bit-ו-redirect)

### דף סליקה מסוג Redirect

[](#דף-סליקה-מסוג-redirect)

גביה באמצעות Bit, Google Pay, Apple Pay, 3DS אפשרית באמצעות הגדרת דף סליקה בשיטת Redirect.

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Environment Settings** &gt; **PCI Mode** &gt; בחרו **"Redirect"**

**ב-.env:**

```
OFFICEGUY_PCI_MODE=redirect
OFFICEGUY_BIT_ENABLED=true
```

**בקוד:**

```
// חיוב עם Bit
$result = BitPaymentService::processOrder(
    $order,
    route('checkout.success'),
    route('checkout.failed'),
    route('officeguy.webhook.bit')
);

if ($result['success']) {
    return redirect($result['redirect_url']);
}
```

**Webhook ל-Bit:**

```
POST /officeguy/webhook/bit

```

החבילה מטפלת אוטומטית ב-webhook ומעדכנת את סטטוס ההזמנה.

> ⚠️ **שימו לב:** מצב Redirect לא תומך בהוראות קבע, שמירת פרטי תשלום, ותפיסת מסגרת.

---

מיזוג לקוחות אוטומטי
--------------------

[](#מיזוג-לקוחות-אוטומטי)

### מניעת כפילות כרטיסי לקוח ב-SUMIT

[](#מניעת-כפילות-כרטיסי-לקוח-ב-sumit)

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

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Customer Merging** &gt; סמנו **"Enable Customer Merging"**

**ב-.env:**

```
OFFICEGUY_MERGE_CUSTOMERS=true
```

**איך זה עובד:**

1. בעת יצירת מסמך, המערכת מחפשת לקוח קיים לפי מייל או מזהה
2. אם נמצא - המסמך מקושר ללקוח הקיים
3. אם לא נמצא - נוצר לקוח חדש

### סנכרון לקוחות עם מודל מקומי (ללא שינוי קוד)

[](#סנכרון-לקוחות-עם-מודל-מקומי-ללא-שינוי-קוד)

ניתן לסנכרן לקוחות מ-SUMIT עם מודל הלקוחות המקומי שלכם **ללא לגעת בקוד המודל**.

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Customer Merging**

**הגדרות:**

הגדרהתיאורדוגמהEnable Customer Mergingהפעלת מיזוג ב-SUMIT`true`Enable Local Customer Syncהפעלת סנכרון מקומי`true`Customer Model Classשם מלא של מודל הלקוח`App\Models\User`**מיפוי שדות לקוח:**

שדהברירת מחדלתיאורEmail Field`email`שדה אימייל (מזהה ייחודי)Name Field`name`שדה שם מלאPhone Field`phone`שדה טלפוןFirst Name Field-שדה שם פרטי (אם נפרד)Last Name Field-שדה שם משפחה (אם נפרד)Company Field-שדה שם חברהAddress Field-שדה כתובתCity Field-שדה עירSUMIT ID Field`sumit_customer_id`שדה לשמירת מזהה SUMIT**דוגמה - חיבור למודל User:**

1. הוסיפו עמודה לטבלת users:

```
php artisan make:migration add_sumit_customer_id_to_users_table
```

```
Schema::table('users', function (Blueprint $table) {
    $table->string('sumit_customer_id')->nullable()->index();
});
```

2. ב-Admin Panel הגדירו:

    - Customer Model Class: `App\Models\User`
    - Email Field: `email`
    - Name Field: `name`
    - SUMIT ID Field: `sumit_customer_id`
3. הפעילו סנכרון אוטומטי ב-Listener:

```
// app/Providers/EventServiceProvider.php
use OfficeGuy\LaravelSumitGateway\Events\SumitWebhookReceived;
use OfficeGuy\LaravelSumitGateway\Listeners\CustomerSyncListener;

protected $listen = [
    SumitWebhookReceived::class => [
        CustomerSyncListener::class,
    ],
];
```

**שימוש ב-CustomerMergeService:**

```
use OfficeGuy\LaravelSumitGateway\Services\CustomerMergeService;

// סנכרון ידני של לקוח מ-SUMIT
$mergeService = app(CustomerMergeService::class);

// מציאת לקוח לפי SUMIT ID
$customer = $mergeService->findBySumitId('12345');

// מציאת לקוח לפי אימייל
$customer = $mergeService->findByEmail('customer@example.com');

// סנכרון לקוח מנתוני SUMIT
$sumitData = [
    'ID' => '12345',
    'Email' => 'customer@example.com',
    'FirstName' => 'John',
    'LastName' => 'Doe',
    'Phone' => '0501234567',
];
$localCustomer = $mergeService->syncFromSumit($sumitData);
```

**יתרונות:**

- ✅ אין צורך לשנות את קוד המודל
- ✅ הגדרה מלאה דרך Admin Panel
- ✅ סנכרון אוטומטי כשמתקבל webhook מ-SUMIT
- ✅ מניעת כפילויות לקוחות
- ✅ שיפור חוויית לקוח - זיהוי לקוחות חוזרים

---

מודל Order (Payable)
--------------------

[](#מודל-order-payable)

החבילה דורשת שמודל ההזמנה יממש `OfficeGuy\LaravelSumitGateway\Contracts\Payable`.

### אפשרות 1: מיפוי שדות מ-Admin Panel (ללא שינוי קוד)

[](#אפשרות-1-מיפוי-שדות-מ-admin-panel-ללא-שינוי-קוד)

ניתן לחבר כל מודל קיים מבלי לשנות את הקוד שלו. ראו סעיף [עמוד תשלום ציבורי](#%D7%A2%D7%9E%D7%95%D7%93-%D7%AA%D7%A9%D7%9C%D7%95%D7%9D-%D7%A6%D7%99%D7%91%D7%95%D7%A8%D7%99-public-checkout-page).

### אפשרות 2: שימוש ב-Trait

[](#אפשרות-2-שימוש-ב-trait)

```
class Order extends Model implements Payable {
    use \OfficeGuy\LaravelSumitGateway\Support\Traits\PayableAdapter;
}
```

כדאי להעמיס (eager load) יחסי items/fees.

### קונפיגורציה

[](#קונפיגורציה)

```
'order' => [
    'model' => App\Models\Order::class,
    // או
    'resolver' => fn($id) => App\Models\Order::with('items','fees')->find($id),
],
```

---

מסלולים (Routes)
----------------

[](#מסלולים-routes)

תחת prefix (ברירת מחדל `officeguy`):

מסלולסוגתיאור`callback/card`GETחזרת Redirect מכרטיס`webhook/bit`POSTIPN ל-Bit`checkout/charge`POSTמסלול סליקה מובנה (אופציונלי)`checkout/{id}`GET/POSTעמוד תשלום ציבורי (אופציונלי)מסלולי הצלחה/כישלון: מוגדרים ב-config `routes.success` / `routes.failed`.

---

Filament Admin Panel
--------------------

[](#filament-admin-panel)

### עמודים וניהול

[](#עמודים-וניהול)

- **Gateway Settings** - הגדרות שער התשלום (ניווט: SUMIT Gateway)
- **משאבי לקוח** - טרנזקציות, מסמכים, אמצעי תשלום (Client Panel)

### גישה להגדרות

[](#גישה-להגדרות)

```
Admin Panel > SUMIT Gateway > Gateway Settings

```

---

SSL
---

[](#ssl)

ה-HTTP client משתמש ב-`ssl_verify` (ברירת מחדל true). לשימוש dev בלבד ניתן לכבות:

```
OFFICEGUY_SSL_VERIFY=false
```

---

לוגים
-----

[](#לוגים)

הפעלת לוגים לניטור ודיבוג:

```
OFFICEGUY_LOGGING=true
OFFICEGUY_LOG_CHANNEL=stack
```

> 🔒 נתונים רגישים (מספר כרטיס/CVV) מנוקים אוטומטית מהלוגים.

---

Multi-Vendor
------------

[](#multi-vendor)

### תמיכה בריבוי מוכרים

[](#תמיכה-בריבוי-מוכרים)

תמיכה בשוק (marketplace) עם credentials נפרדים לכל ספק.

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Multi-Vendor**

**הגדרות:**

- **Enable Multi-Vendor** - הפעלת מצב ריבוי מוכרים
- **Validate Vendor Credentials** - אימות פרטי ספק
- **Allow Authorize Only** - אפשרות תפיסת מסגרת לספקים

**ב-.env:**

```
OFFICEGUY_MULTIVENDOR_ENABLED=true
OFFICEGUY_MULTIVENDOR_VALIDATE_CREDENTIALS=true
OFFICEGUY_MULTIVENDOR_ALLOW_AUTHORIZE=false
```

**בקוד:**

```
use OfficeGuy\LaravelSumitGateway\Models\VendorCredential;
use OfficeGuy\LaravelSumitGateway\Services\MultiVendorPaymentService;

// שמירת credentials לספק
VendorCredential::create([
    'vendor_type' => get_class($vendor),
    'vendor_id' => $vendor->id,
    'company_id' => '12345',
    'api_key' => 'your-api-key',
]);

// חיוב הזמנה מרובת ספקים
$result = MultiVendorPaymentService::processMultiVendorCharge($order, $paymentsCount);
```

**Resolver לזיהוי ספק:**

```
// config/officeguy.php
'multivendor' => [
    'vendor_resolver' => fn(array $item) => \App\Models\Vendor::find($item['vendor_id']),
],
```

---

תרומות (Donations)
------------------

[](#תרומות-donations)

### תמיכה במוצרי תרומה

[](#תמיכה-במוצרי-תרומה)

הפקת קבלת תרומה אוטומטית במקום חשבונית רגילה.

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Donations**

**הגדרות:**

- **Enable Donations** - הפעלת תמיכה בתרומות
- **Allow Mixed Cart** - אפשרות לשלב תרומות עם מוצרים רגילים
- **Document Type** - סוג מסמך (Donation Receipt / Invoice)

**ב-.env:**

```
OFFICEGUY_DONATIONS_ENABLED=true
OFFICEGUY_DONATIONS_ALLOW_MIXED=false
OFFICEGUY_DONATIONS_DOCUMENT_TYPE=320   # 320=קבלת תרומה
```

**בקוד:**

```
use OfficeGuy\LaravelSumitGateway\Services\DonationService;

// בדיקה אם עגלה מכילה תרומות ומוצרים רגילים
$validation = DonationService::validateCart($order);
if (!$validation['valid']) {
    return redirect()->back()->with('error', $validation['message']);
}

// קבלת סוג המסמך המתאים
$docType = DonationService::getDocumentType($order);
```

---

Upsell / CartFlows
------------------

[](#upsell--cartflows)

### חיוב מוצרי upsell

[](#חיוב-מוצרי-upsell)

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

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Upsell / CartFlows**

**הגדרות:**

- **Enable Upsell** - הפעלת upsell
- **Require Saved Token** - דרישת טוקן שמור
- **Max Upsells Per Order** - מקסימום upsells להזמנה

**ב-.env:**

```
OFFICEGUY_UPSELL_ENABLED=true
OFFICEGUY_UPSELL_REQUIRE_TOKEN=true
OFFICEGUY_UPSELL_MAX_PER_ORDER=5
```

**בקוד:**

```
use OfficeGuy\LaravelSumitGateway\Services\UpsellService;

// חיוב עם טוקן ידוע
$result = UpsellService::processUpsellCharge($upsellOrder, $token, $parentOrderId);

// חיוב עם זיהוי אוטומטי של הטוקן
$result = UpsellService::processUpsellWithAutoToken($upsellOrder, $parentOrderId, $customer);
```

---

יצירת משתמש אוטומטית לאחר תשלום (v1.14.0+)
------------------------------------------

[](#יצירת-משתמש-אוטומטית-לאחר-תשלום-v1140)

החבילה תוכל ליצור באופן אוטומטי חשבון משתמש עבור קונים אורחים (לא מחוברים) לאחר השלמת תשלום מוצלח.

### תכונות

[](#תכונות)

- ✅ **יצירה אוטומטית**: נוצר חשבון User + Client אוטומטית לאחר תשלום מוצלח
- ✅ **סיסמה זמנית**: נוצרת סיסמה אקראית בת 12 תווים עם תוקף של 7 ימים (ניתן להגדרה)
- ✅ **מייל ברוכים הבאים**: נשלח מייל עם פרטי התחברות, הסיסמה הזמנית ופרטי ההזמנה
- ✅ **טיפול במשתמשים קיימים**: אם קיים משתמש עם אותו אימייל, ההזמנה תקושר אליו ללא יצירת משתמש כפול
- ✅ **ניתן להשבתה**: ניתן להפעיל/להשבית את התכונה דרך Admin Panel או .env

### הפעלה והגדרות

[](#הפעלה-והגדרות)

**ב-Admin Panel:**נווטו ל-**SUMIT Gateway** &gt; **Gateway Settings** &gt; **User Management**

**הגדרות זמינות:**

- **Auto Create Guest User** - הפעלת/השבתת יצירת משתמש אוטומטית (ברירת מחדל: מופעל)
- **Guest Password Expiry Days** - מספר ימים עד לתוקף הסיסמה הזמנית (ברירת מחדל: 7)

**ב-.env:**

```
OFFICEGUY_AUTO_CREATE_GUEST_USER=true
OFFICEGUY_GUEST_PASSWORD_EXPIRY_DAYS=7
```

### איך זה עובד?

[](#איך-זה-עובד)

1. **לקוח אורח מבצע תשלום** - לקוח שאינו מחובר מבצע תשלום מוצלח דרך עמוד התשלום
2. **אירוע PaymentCompleted** - החבילה משדרת את האירוע `PaymentCompleted`
3. **AutoCreateUserListener מופעל** - Listener בודק אם ההזמנה היא של אורח (user\_id = null)
4. **בדיקת משתמש קיים** - אם קיים משתמש עם אותו אימייל, ההזמנה מקושרת אליו
5. **יצירת משתמש חדש** - אם לא קיים משתמש:
    - נוצר User עם פרטים מההזמנה
    - נוצרת סיסמה זמנית (12 תווים, תוקף 7 ימים)
    - נוצר Client מקושר למשתמש
    - ההזמנה מקושרת למשתמש וללקוח
6. **שליחת מייל** - נשלח מייל ברוכים הבאים עם:
    - פרטי ההתחברות (אימייל וסיסמה זמנית)
    - קישור לפורטל הלקוחות
    - פרטי ההזמנה
    - הוראות שימוש

### דוגמת מייל

[](#דוגמת-מייל)

המייל שנשלח ללקוח כולל:

- כותרת: "תשלום בוצע בהצלחה - פרטי התחברות לפורטל הלקוחות"
- הסיסמה הזמנית בולטת ומסומנת
- פרטי התחברות: אימייל, סיסמה, תוקף
- פרטי ההזמנה: מספר הזמנה, סכום, תאריך
- קישור ישיר לפורטל הלקוחות
- הוראות חשובות ושלבים הבאים

### מה נוצר?

[](#מה-נוצר)

**User:**

```
[
    'name' => 'שם מלא מההזמנה',
    'first_name' => 'שם פרטי',
    'last_name' => 'שם משפחה',
    'email' => 'client@example.com',
    'phone' => 'טלפון מההזמנה',
    'company' => 'שם החברה (אם קיים)',
    'address' => 'כתובת',
    'city' => 'עיר',
    'country' => 'IL',
    'password' => 'סיסמה מוצפנת (Hash)',
    'role' => 'client',
    'email_verified_at' => now(),
    'has_temporary_password' => true,
    'temporary_password_expires_at' => now()->addDays(7),
    'temporary_password_created_by' => null, // נוצרה אוטומטית
]
```

**Client:**

```
Client::createFromUser($user);
// יוצר Client עם כל הפרטים מהמשתמש
```

**Order:**

```
$order->update([
    'user_id' => $user->id,
    'client_id' => $client->id,
]);
```

### השבתת התכונה

[](#השבתת-התכונה)

אם ברצונך להשבית את יצירת המשתמש האוטומטית:

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **User Management** ושנו את **Auto Create Guest User** ל-OFF

**או ב-.env:**

```
OFFICEGUY_AUTO_CREATE_GUEST_USER=false
```

### קבצים קשורים

[](#קבצים-קשורים)

- `src/Listeners/AutoCreateUserListener.php` - Listener המטפל ביצירת המשתמש
- `app/Mail/GuestWelcomeWithPasswordMail.php` - Mailable לשליחת המייל
- `resources/views/emails/guest-welcome-with-password.blade.php` - תבנית המייל
- `config/officeguy.php:108-123` - הגדרות

---

Secure Success Page - עמוד הצלחה מאובטח (v1.2.0+)
-------------------------------------------------

[](#secure-success-page---עמוד-הצלחה-מאובטח-v120)

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

### למה זה חשוב?

[](#למה-זה-חשוב)

**הבעיה:**עמודי הצלחה מסורתיים משתמשים ב-URLs פשוטים כמו `/order/success/264` שכל אחד יכול לנחש ולגשת אליהם, מה שחושף:

- פרטי תשלום אישיים
- מספרי הזמנות
- פרטי לקוח
- סכומי תשלום

**הפתרון:**מערכת אבטחה 7-שכבות המייצרת URLs חד-פעמיים עם טוקנים קריפטוגרפיים.

### 7 שכבות האבטחה

[](#7-שכבות-האבטחה)

1. **Rate Limiting** - הגבלת ניסיונות גישה למניעת Brute Force
2. **Signed URL** - חתימת Laravel HMAC למניעת זיוף URL
3. **Token Existence** - בדיקה שהטוקן קיים במסד הנתונים
4. **Token Validity** - בדיקה שהטוקן לא פג תוקף (TTL)
5. **Single Use** - טוקן ניתן לשימוש חד-פעמי בלבד (נצרך אחרי גישה)
6. **Nonce Matching** - הגנת Replay Attack באמצעות nonce קריפטוגרפי
7. **Identity Proof** - אימות משתמש מחובר או הוכחת בעלות קריפטוגרפית לאורחים

### איך זה עובד?

[](#איך-זה-עובד-1)

#### זרימת העבודה:

[](#זרימת-העבודה)

```
1. תשלום מוצלח
   ↓
2. CardCallbackController מייצר טוקן (128 תווים אקראיים)
   ↓
3. Nonce קריפטוגרפי (64 תווים) נוצר
   ↓
4. SHA256 hash נשמר ב-DB (לא הטוקן הגולמי!)
   ↓
5. Laravel signed URL נוצר עם הטוקן והנונס
   ↓
6. הלקוח מופנה ל-URL המאובטח
   ↓
7. SecureSuccessController מאמת את 7 השכבות
   ↓
8. הטוקן נצרך (consumed = true)
   ↓
9. עמוד ההצלחה מוצג (פעם אחת בלבד!)

```

#### דוגמה ל-URL מאובטח:

[](#דוגמה-ל-url-מאובטח)

```
https://nm-digitalhub.com/officeguy/success?
  token=a1b2c3d4e5f6...                     ← 128 תווים אקראיים
  &nonce=9f8e7d6c5b4a...                    ← 64 תווים nonce
  &signature=7c1a2b3d4e5f...                ← חתימת Laravel
  &expires=1703462400                       ← תוקף Signed URL

```

### הפעלה והגדרות

[](#הפעלה-והגדרות-1)

**ב-Admin Panel:**נווטו ל-**SUMIT Gateway** &gt; **Gateway Settings** &gt; **Secure Success Page (v1.2.0+)**

**הגדרות זמינות:**

הגדרהברירת מחדלתיאורEnable Secure Success URLs`true`הפעלת/השבתת מערכת האבטחהToken Validity (Hours)`24`כמה זמן הטוקן תקף (1-168 שעות)Rate Limit - Max Attempts`10`מספר ניסיונות גישה מקסימלי לכל IPRate Limit - Decay Time`1`חלון זמן להגבלת קצב (דקות)**ב-.env:**

```
OFFICEGUY_SUCCESS_SECURE_ENABLED=true
OFFICEGUY_SUCCESS_TOKEN_TTL=24
OFFICEGUY_SUCCESS_RATE_LIMIT_MAX=10
OFFICEGUY_SUCCESS_RATE_LIMIT_DECAY=1
```

### דוגמאות שימוש

[](#דוגמאות-שימוש)

#### בקוד - יצירת URL מאובטח:

[](#בקוד---יצירת-url-מאובטח)

```
use OfficeGuy\LaravelSumitGateway\Services\SecureSuccessUrlGenerator;

$generator = app(SecureSuccessUrlGenerator::class);

// יצירת URL מאובטח עבור הזמנה
$secureUrl = $generator->generate($order);

// הפניה ללקוח
return redirect()->away($secureUrl);
```

#### בקוד - אימות גישה:

[](#בקוד---אימות-גישה)

```
use OfficeGuy\LaravelSumitGateway\Services\SuccessAccessValidator;

$validator = app(SuccessAccessValidator::class);

// אימות כל 7 השכבות
$result = $validator->validate($request);

if ($result->isValid) {
    // הצג עמוד הצלחה
    return view('success', ['order' => $result->order]);
}

// גישה נדחתה
return view('errors.access-denied', [
    'error' => $result->error,
]);
```

### דגשים חשובים

[](#דגשים-חשובים)

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

✅ **אבטחה לאורחים:**גם לקוחות לא מחוברים מוגנים באמצעות הוכחת בעלות קריפטוגרפית (nonce matching).

✅ **תאימות לאחור:**אם המערכת מושבתת או ההזמנה לא מיישמת את ממשק `Payable`, המערכת חוזרת ל-redirect המסורתי.

✅ **מניעת Replay Attacks:**השימוש ב-nonce מונע שימוש חוזר בטוקן גם אם מישהו מצליח לגנוב אותו.

### השבתת התכונה

[](#השבתת-התכונה-1)

אם ברצונך לחזור ל-redirect המסורתי (לא מומלץ):

**ב-Admin Panel:**נווטו ל-**Gateway Settings** &gt; **Secure Success Page** ושנו את **Enable Secure Success URLs** ל-OFF

**או ב-.env:**

```
OFFICEGUY_SUCCESS_SECURE_ENABLED=false
```

### קבצים קשורים

[](#קבצים-קשורים-1)

- `src/Services/SecureSuccessUrlGenerator.php` - יצירת URLs מאובטחים
- `src/Services/SuccessAccessValidator.php` - אימות 7 השכבות
- `src/Http/Controllers/SecureSuccessController.php` - Controller עמוד הצלחה
- `src/Http/Controllers/CardCallbackController.php` - שימוש ב-SecureSuccessUrlGenerator
- `src/Models/OrderSuccessToken.php` - מודל הטוקנים
- `src/Models/OrderSuccessAccessLog.php` - לוג ניסיונות גישה
- `database/migrations/2025_12_18_000001_create_order_success_tokens_table.php`
- `database/migrations/2025_12_18_000002_create_order_success_access_log_table.php`
- `config/officeguy.php:192-222` - הגדרות

### אירועים

[](#אירועים)

אירועתיאורPayload`SuccessPageAccessed`גישה מוצלחת לעמוד הצלחה`$order`, `$token`, `$user`**דוגמת Listener:**

```
use OfficeGuy\LaravelSumitGateway\Events\SuccessPageAccessed;

Event::listen(SuccessPageAccessed::class, function($event) {
    Log::info('Success page accessed', [
        'order_id' => $event->order->id,
        'user_id' => $event->user?->id ?? 'guest',
        'token_id' => $event->token->id,
    ]);
});
```

---

אירועים (Events)
----------------

[](#אירועים-events)

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

אירועתיאור`PaymentCompleted`תשלום הצליח`PaymentFailed`תשלום נכשל`DocumentCreated`מסמך נוצר`StockSynced`מלאי סונכרן`BitPaymentCompleted`תשלום Bit הושלם`SubscriptionCreated`מנוי נוצר`SubscriptionCharged`מנוי חויב`SubscriptionChargesFailed`חיוב מנוי נכשל`SubscriptionCancelled`מנוי בוטל`MultiVendorPaymentCompleted`תשלום מרובה-ספקים הצליח`MultiVendorPaymentFailed`תשלום מרובה-ספקים נכשל`UpsellPaymentCompleted`תשלום upsell הצליח`UpsellPaymentFailed`תשלום upsell נכשל**האזנה לאירועים:**

```
// app/Providers/EventServiceProvider.php
use OfficeGuy\LaravelSumitGateway\Events\PaymentCompleted;

protected $listen = [
    PaymentCompleted::class => [
        \App\Listeners\SendPaymentConfirmation::class,
        \App\Listeners\UpdateOrderStatus::class,
    ],
];
```

**דוגמת Listener:**

```
namespace App\Listeners;

use OfficeGuy\LaravelSumitGateway\Events\PaymentCompleted;

class SendPaymentConfirmation
{
    public function handle(PaymentCompleted $event): void
    {
        $orderId = $event->orderId;
        $transactionId = $event->transactionId;

        // שליחת אימייל אישור
        Mail::to($event->customerEmail)->send(new PaymentConfirmed($orderId));
    }
}
```

---

Custom Event Webhooks
---------------------

[](#custom-event-webhooks)

### הגדרת Webhooks מה-Admin Panel

[](#הגדרת-webhooks-מה-admin-panel)

במקום ליצור Listeners בקוד, ניתן להגדיר Webhooks מותאמים אישית ישירות מה-Admin Panel. המערכת תשלח התראות HTTP לכל URL שתגדירו כאשר מתרחשים אירועים.

**ב-Admin Panel:**נווטו ל-**SUMIT Gateway** &gt; **Gateway Settings** &gt; **Custom Event Webhooks**

**אירועים נתמכים:**

אירועשדה בהגדרותתיאורPayment Completed`webhook_payment_completed`תשלום הושלם בהצלחהPayment Failed`webhook_payment_failed`תשלום נכשלDocument Created`webhook_document_created`מסמך (חשבונית/קבלה) נוצרSubscription Created`webhook_subscription_created`מנוי חדש נוצרSubscription Charged`webhook_subscription_charged`מנוי חויבBit Payment Completed`webhook_bit_payment_completed`תשלום Bit הושלםStock Synced`webhook_stock_synced`מלאי סונכרן**הגדרת סוד לאימות:**הגדירו `Webhook Secret` ב-Admin Panel. המערכת תשלח חתימה בכותרת `X-Webhook-Signature` לאימות מקור הבקשה.

**דוגמת Payload:**

```
{
    "event": "payment_completed",
    "timestamp": "2024-01-15T10:30:00+02:00",
    "order_id": 123,
    "transaction_id": "TXN_12345",
    "amount": 99.00,
    "currency": "ILS",
    "customer_email": "customer@example.com"
}
```

**כותרות HTTP:**

```
Content-Type: application/json
X-Webhook-Event: payment_completed
X-Webhook-Signature: sha256=abc123...
X-Webhook-Timestamp: 2024-01-15T10:30:00+02:00

```

**אימות חתימה בשרת שלכם:**

```
function verifyWebhook(Request $request): bool
{
    $signature = $request->header('X-Webhook-Signature');
    $payload = $request->getContent();
    $secret = config('your-webhook-secret');

    $expectedSignature = hash_hmac('sha256', $payload, $secret);
    return hash_equals($expectedSignature, $signature);
}
```

**שימוש ב-WebhookService ישירות (אופציונלי):**

```
use OfficeGuy\LaravelSumitGateway\Services\WebhookService;

// שליחת webhook ידנית
$webhookService = app(WebhookService::class);
$webhookService->send('payment_completed', [
    'order_id' => 123,
    'amount' => 99.00,
]);
```

---

Webhook Events Resource (Admin Panel)
-------------------------------------

[](#webhook-events-resource-admin-panel)

### צפייה ב-Webhook Events

[](#צפייה-ב-webhook-events)

משאב מלא לצפייה וניהול כל אירועי ה-Webhook, כולל חיבור למשאבים קיימים לבניית אוטומציות.

**ב-Admin Panel:**נווטו ל-**SUMIT Gateway** &gt; **Webhook Events**

### תכונות הממשק

[](#תכונות-הממשק)

**רשימת אירועים:**

- צפייה בכל האירועים שנשלחו
- סינון לפי סוג אירוע, סטטוס, טווח תאריכים
- חיפוש לפי מייל לקוח או מזהה
- מיון לפי תאריך, סטטוס, HTTP status
- Badge עם מספר אירועים שנכשלו

**פעולות:**

- **Retry** - שליחה חוזרת של webhook שנכשל
- **Retry All Failed** - שליחה חוזרת לכל האירועים הכושלים
- **Clear Sent Events** - מחיקת אירועים ישנים (7+ ימים)
- **Copy Payload** - העתקת ה-payload

**חיבור למשאבים קיימים:**כל אירוע מקושר אוטומטית למשאבים הרלוונטיים:

- **Transaction** - לחיצה מעבירה לעמוד הטרנזקציה
- **Document** - לחיצה מעבירה לעמוד המסמך
- **Token** - לחיצה מעבירה לעמוד הטוקן
- **Subscription** - לחיצה מעבירה לעמוד המנוי

**סטטיסטיקות (Widget):**

- אירועים היום
- אחוז הצלחה
- אירועים שנכשלו
- זמן תגובה ממוצע
- גרף 7 ימים אחרונים

### שימוש בסיסי

[](#שימוש-בסיסי)

#### 1. הגדרת Webhook בשרת חיצוני

[](#1-הגדרת-webhook-בשרת-חיצוני)

כדי לקבל התראות, צרו endpoint בשרת שלכם שמקבל בקשות POST:

```
// routes/api.php
Route::post('/webhooks/sumit', [WebhookController::class, 'handle']);
```

```
// app/Http/Controllers/WebhookController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class WebhookController extends Controller
{
    public function handle(Request $request)
    {
        // 1. אימות החתימה
        $signature = $request->header('X-Webhook-Signature');
        $payload = $request->getContent();
        $secret = config('services.sumit.webhook_secret');

        $expectedSignature = hash_hmac('sha256', $payload, $secret);

        if (!hash_equals($expectedSignature, $signature)) {
            Log::warning('Invalid webhook signature');
            return response('Invalid signature', 401);
        }

        // 2. עיבוד האירוע
        $event = $request->input('event');
        $data = $request->all();

        switch ($event) {
            case 'payment_completed':
                $this->handlePaymentCompleted($data);
                break;
            case 'payment_failed':
                $this->handlePaymentFailed($data);
                break;
            case 'document_created':
                $this->handleDocumentCreated($data);
                break;
            case 'subscription_charged':
                $this->handleSubscriptionCharged($data);
                break;
        }

        return response('OK', 200);
    }

    protected function handlePaymentCompleted(array $data): void
    {
        $orderId = $data['order_id'];
        $transactionId = $data['transaction_id'];
        $amount = $data['amount'];

        // עדכון הזמנה
        $order = Order::find($orderId);
        $order->update([
            'status' => 'paid',
            'paid_at' => now(),
        ]);

        // שליחת אישור ללקוח
        Mail::to($data['customer_email'])->send(new PaymentConfirmation($order));

        // עדכון CRM
        CrmService::updateCustomer($data['customer_email'], [
            'last_purchase' => now(),
            'total_spent' => $amount,
        ]);
    }

    protected function handlePaymentFailed(array $data): void
    {
        $orderId = $data['order_id'];
        $error = $data['error'] ?? 'Unknown error';

        // עדכון הזמנה
        Order::find($orderId)?->update(['status' => 'payment_failed']);

        // התראה לצוות
        Notification::route('slack', config('services.slack.webhook'))
            ->notify(new PaymentFailedNotification($orderId, $error));
    }

    protected function handleDocumentCreated(array $data): void
    {
        // שמירת קישור למסמך
        $orderId = $data['order_id'];
        $documentUrl = $data['document_url'] ?? null;

        Order::find($orderId)?->update(['invoice_url' => $documentUrl]);
    }

    protected function handleSubscriptionCharged(array $data): void
    {
        $subscriptionId = $data['subscription_id'];
        $amount = $data['amount'];

        // רישום חיוב
        SubscriptionCharge::create([
            'subscription_id' => $subscriptionId,
            'amount' => $amount,
            'charged_at' => now(),
        ]);
    }
}
```

#### 2. הגדרת URL ב-Admin Panel

[](#2-הגדרת-url-ב-admin-panel)

1. גשו ל-**SUMIT Gateway** &gt; **Gateway Settings** &gt; **Custom Event Webhooks**
2. הזינו את ה-URL של ה-endpoint שלכם בשדה המתאים
3. הגדירו סוד (Secret) לאימות החתימה
4. שמרו את ההגדרות

### שימוש מתקדם בקוד

[](#שימוש-מתקדם-בקוד)

#### שליפת אירועים ב-Eloquent

[](#שליפת-אירועים-ב-eloquent)

```
use OfficeGuy\LaravelSumitGateway\Models\WebhookEvent;

// קבלת כל האירועים שנכשלו
$failedEvents = WebhookEvent::failed()->get();

// קבלת אירועים של לקוח ספציפי
$customerEvents = WebhookEvent::forCustomer('customer@example.com')->get();

// קבלת אירועים מסוג מסוים
$paymentEvents = WebhookEvent::ofType('payment_completed')
    ->with(['transaction', 'document'])
    ->get();

// אירועים מוכנים לשליחה חוזרת
$pendingRetries = WebhookEvent::readyForRetry()->get();

// אירועים ממוינים לפי תאריך
$recentEvents = WebhookEvent::orderBy('created_at', 'desc')
    ->limit(100)
    ->get();
```

#### גישה למשאבים מקושרים

[](#גישה-למשאבים-מקושרים)

```
// לכל אירוע יש גישה למשאבים הקשורים אליו
foreach ($paymentEvents as $event) {
    // גישה לטרנזקציה
    $transaction = $event->transaction;
    if ($transaction) {
        echo "Transaction ID: {$transaction->payment_id}";
        echo "Amount: {$transaction->amount}";
    }

    // גישה למסמך
    $document = $event->document;
    if ($document) {
        echo "Document Number: {$document->document_number}";
        echo "Document URL: {$document->url}";
    }

    // גישה לטוקן
    $token = $event->token;
    if ($token) {
        echo "Card: ****{$token->last_digits}";
    }

    // גישה למנוי
    $subscription = $event->subscription;
    if ($subscription) {
        echo "Subscription: {$subscription->name}";
        echo "Next Charge: {$subscription->next_charge_at}";
    }

    // גישה להזמנה (polymorphic)
    $order = $event->order;
    if ($order) {
        echo "Order ID: {$order->id}";
    }
}
```

#### שליחה חוזרת של אירועים

[](#שליחה-חוזרת-של-אירועים)

```
use OfficeGuy\LaravelSumitGateway\Services\WebhookService;

// שליחה חוזרת של אירוע בודד
$event = WebhookEvent::find(123);
if ($event->canRetry()) {
    $webhookService = app(WebhookService::class);
    $success = $webhookService->send($event->event_type, $event->payload);

    if ($success) {
        $event->markAsSent(200);
    } else {
        $event->scheduleRetry(5); // retry in 5 minutes
    }
}

// שליחה חוזרת לכל האירועים שנכשלו
$failedEvents = WebhookEvent::failed()->get();
foreach ($failedEvents as $event) {
    if ($event->canRetry()) {
        $event->scheduleRetry();
    }
}
```

#### יצירת אירוע ידנית

[](#יצירת-אירוע-ידנית)

```
use OfficeGuy\LaravelSumitGateway\Models\WebhookEvent;

// יצירת אירוע חדש
$event = WebhookEvent::createEvent('payment_completed', [
    'order_id' => 123,
    'amount' => 99.00,
    'currency' => 'ILS',
    'customer_email' => 'customer@example.com',
], [
    'transaction_id' => $transaction->id,
    'document_id' => $document->id,
    'webhook_url' => 'https://your-site.com/webhook',
]);

// סימון כנשלח
$event->markAsSent(200, ['received' => true]);

// סימון ככישלון
$event->markAsFailed('Connection timeout', 504);
```

### בניית אוטומציות

[](#בניית-אוטומציות)

#### דוגמה: סנכרון עם CRM

[](#דוגמה-סנכרון-עם-crm)

```
// app/Console/Commands/SyncWebhooksToCrm.php
namespace App\Console\Commands;

use Illuminate\Console\Command;
use OfficeGuy\LaravelSumitGateway\Models\WebhookEvent;
use App\Services\CrmService;

class SyncWebhooksToCrm extends Command
{
    protected $signature = 'crm:sync-webhooks';
    protected $description = 'Sync payment webhooks to CRM';

    public function handle(CrmService $crm)
    {
        // קבלת כל האירועים שטרם סונכרנו
        $events = WebhookEvent::ofType('payment_completed')
            ->sent()
            ->where('synced_to_crm', false)
            ->with(['transaction', 'document'])
            ->get();

        foreach ($events as $event) {
            $crm->recordPurchase([
                'email' => $event->customer_email,
                'amount' => $event->amount,
                'currency' => $event->currency,
                'transaction_id' => $event->transaction?->payment_id,
                'invoice_url' => $event->document?->url,
            ]);

            $event->update(['synced_to_crm' => true]);
        }

        $this->info("Synced {$events->count()} events to CRM");
    }
}
```

#### דוגמה: דוח יומי

[](#דוגמה-דוח-יומי)

```
// app/Console/Commands/WebhookDailyReport.php
namespace App\Console\Commands;

use Illuminate\Console\Command;
use OfficeGuy\LaravelSumitGateway\Models\WebhookEvent;
use Illuminate\Support\Facades\Mail;

class WebhookDailyReport extends Command
{
    protected $signature = 'webhooks:daily-report';
    protected $description = 'Send daily webhook statistics report';

    public function handle()
    {
        $today = now()->startOfDay();

        $stats = [
            'total' => WebhookEvent::whereDate('created_at', $today)->count(),
            'sent' => WebhookEvent::sent()->whereDate('created_at', $today)->count(),
            'failed' => WebhookEvent::failed()->whereDate('created_at', $today)->count(),
            'by_type' => WebhookEvent::whereDate('created_at', $today)
                ->selectRaw('event_type, count(*) as count')
                ->groupBy('event_type')
                ->pluck('count', 'event_type'),
            'total_amount' => WebhookEvent::ofType('payment_completed')
                ->whereDate('created_at', $today)
                ->sum('amount'),
        ];

        // שליחת דוח במייל
        Mail::to('admin@example.com')->send(new WebhookStatsReport($stats));

        $this->info("Report sent. Total events: {$stats['total']}");
    }
}
```

#### דוגמה: ניטור כשלונות

[](#דוגמה-ניטור-כשלונות)

```
// app/Console/Commands/MonitorWebhookFailures.php
namespace App\Console\Commands;

use Illuminate\Console\Command;
use OfficeGuy\LaravelSumitGateway\Models\WebhookEvent;
use Illuminate\Support\Facades\Notification;
use App\Notifications\WebhookFailureAlert;

class MonitorWebhookFailures extends Command
{
    protected $signature = 'webhooks:monitor';
    protected $description = 'Monitor webhook failures and alert';

    public function handle()
    {
        $failedCount = WebhookEvent::failed()
            ->where('created_at', '>=', now()->subHour())
            ->count();

        if ($failedCount > 10) {
            // שליחת התראה
            Notification::route('slack', config('services.slack.webhook'))
                ->notify(new WebhookFailureAlert($failedCount));

            $this->error("Alert sent: {$failedCount} failures in the last hour");
        } else {
            $this->info("All good: {$failedCount} failures in the last hour");
        }
    }
}
```

### תזמון משימות

[](#תזמון-משימות)

הוסיפו ל-`routes/console.php`:

```
use Illuminate\Support\Facades\Schedule;

// עיבוד webhooks שממתינים לשליחה חוזרת
Schedule::command('sumit:process-webhook-retries')->everyFiveMinutes();

// דוח יומי
Schedule::command('webhooks:daily-report')->dailyAt('09:00');

// ניטור כשלונות
Schedule::command('webhooks:monitor')->everyThirtyMinutes();

// סנכרון עם CRM
Schedule::command('crm:sync-webhooks')->hourly();
```

### סוגי אירועים

[](#סוגי-אירועים)

סוג אירועקבועתיאורשדות עיקרייםPayment Completed`payment_completed`תשלום הושלם בהצלחה`order_id`, `transaction_id`, `amount`, `customer_email`Payment Failed`payment_failed`תשלום נכשל`order_id`, `error`, `customer_email`Document Created`document_created`מסמך נוצר`order_id`, `document_id`, `document_number`, `document_url`Subscription Created`subscription_created`מנוי חדש נוצר`subscription_id`, `customer_email`, `amount`, `interval`Subscription Charged`subscription_charged`מנוי חויב`subscription_id`, `transaction_id`, `amount`Bit Payment`bit_payment_completed`תשלום Bit הושלם`order_id`, `transaction_id`, `amount`Stock Synced`stock_synced`מלאי סונכרן`items_count`, `sync_time`### סטטוסים

[](#סטטוסים)

סטטוסקבועתיאורPending`pending`ממתין לשליחהSent`sent`נשלח בהצלחהFailed`failed`השליחה נכשלהRetrying`retrying`מתוזמן לשליחה חוזרת---

קבלת Webhooks מ-SUMIT (Incoming Webhooks)
-----------------------------------------

[](#קבלת-webhooks-מ-sumit-incoming-webhooks)

### מהי שליחת Webhook מ-SUMIT?

[](#מהי-שליחת-webhook-מ-sumit)

SUMIT יכולה לשלוח התראות (Webhooks) לאפליקציה שלכם כאשר מתרחשות פעולות במערכת SUMIT. זה מאפשר לכם לקבל עדכונים בזמן אמת על פעולות שבוצעו במערכת ניהול החשבונות.

**מידע נוסף:**

- [מדריך שליחת Webhook מ-SUMIT](https://help.sumit.co.il/he/articles/11577644-%D7%A9%D7%9C%D7%99%D7%97%D7%AA-webhook-%D7%9E%D7%9E%D7%A2%D7%A8%D7%9B%D7%AA-%D7%A1%D7%90%D7%9E%D7%99%D7%98)
- [מבוא לטריגרים](https://help.sumit.co.il/he/articles/6324125-%D7%9E%D7%91%D7%95%D7%90-%D7%9C%D7%98%D7%A8%D7%99%D7%92%D7%A8%D7%99%D7%9D)

### סוגי אירועים נתמכים

[](#סוגי-אירועים-נתמכים)

פעולהתיאור`card_created`יצירת כרטיס (לקוח, מסמך, פריט וכו')`card_updated`עדכון כרטיס`card_deleted`מחיקת כרטיס`card_archived`העברת כרטיס לארכיון### סוגי כרטיסים

[](#סוגי-כרטיסים)

סוג כרטיסתיאור`customer`כרטיס לקוח`document`מסמך (חשבונית, קבלה)`transaction`עסקה`item`פריט מלאי`payment`תשלום### כתובות Webhook

[](#כתובות-webhook)

החבילה חושפת מספר endpoints לקבלת webhooks מ-SUMIT:

כתובתתיאור`POST /officeguy/webhook/sumit`Endpoint כללי (זיהוי אוטומטי)`POST /officeguy/webhook/sumit/card-created`יצירת כרטיס`POST /officeguy/webhook/sumit/card-updated`עדכון כרטיס`POST /officeguy/webhook/sumit/card-deleted`מחיקת כרטיס`POST /officeguy/webhook/sumit/card-archived`העברת לארכיון### הגדרת Trigger ב-SUMIT

[](#הגדרת-trigger-ב-sumit)

1. **התקנת מודולים נדרשים ב-SUMIT:**

    - מודול טריגרים
    - מודול API
    - מודול ניהול תצוגות
2. **יצירת תצוגה:**

    - הגדירו אילו כרטיסים יכללו
    - בחרו אילו שדות יועברו ב-webhook
3. **יצירת טריגר:**

    - בחרו תיקייה ותצוגה
    - הגדירו תנאי הפעלה (יצירה/עדכון/מחיקה/ארכיון)
    - בחרו פעולת HTTP
    - הזינו את כתובת ה-webhook שלכם
4. **הגדרת הכתובת:**

    ```
    https://your-domain.com/officeguy/webhook/sumit

    ```

    או לאירוע ספציפי:

    ```
    https://your-domain.com/officeguy/webhook/sumit/card-created

    ```

### SUMIT Webhooks Resource (Admin Panel)

[](#sumit-webhooks-resource-admin-panel)

צפייה בכל ה-webhooks שהתקבלו מ-SUMIT ב-Admin Panel:

**ב-Admin Panel:**נווטו ל-**SUMIT Gateway** &gt; **SUMIT Webhooks**

**תכונות:**

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

**סטטיסטיקות:**

- Webhooks היום
- ממתינים לעיבוד
- אחוז עיבוד
- webhooks שנכשלו

### טיפול ב-Webhooks בקוד

[](#טיפול-ב-webhooks-בקוד)

#### האזנה לאירוע

[](#האזנה-לאירוע)

```
// app/Providers/EventServiceProvider.php
use OfficeGuy\LaravelSumitGateway\Events\SumitWebhookReceived;

protected $listen = [
    SumitWebhookReceived::class => [
        \App\Listeners\HandleSumitWebhook::class,
    ],
];
```

#### יצירת Listener

[](#יצירת-listener)

```
// app/Listeners/HandleSumitWebhook.php
namespace App\Listeners;

use OfficeGuy\LaravelSumitGateway\Events\SumitWebhookReceived;
use OfficeGuy\LaravelSumitGateway\Models\SumitWebhook;

class HandleSumitWebhook
{
    public function handle(SumitWebhookReceived $event): void
    {
        $webhook = $event->webhook;

        switch ($webhook->event_type) {
            case SumitWebhook::TYPE_CARD_CREATED:
                $this->handleCardCreated($webhook);
                break;
            case SumitWebhook::TYPE_CARD_UPDATED:
                $this->handleCardUpdated($webhook);
                break;
            case SumitWebhook::TYPE_CARD_DELETED:
                $this->handleCardDeleted($webhook);
                break;
            case SumitWebhook::TYPE_CARD_ARCHIVED:
                $this->handleCardArchived($webhook);
                break;
        }
    }

    protected function handleCardCreated(SumitWebhook $webhook): void
    {
        // טיפול ביצירת כרטיס
        $cardType = $webhook->card_type;
        $cardId = $webhook->card_id;
        $payload = $webhook->payload;

        if ($cardType === 'customer') {
            // סנכרון לקוח חדש למערכת
            Customer::create([
                'sumit_id' => $cardId,
                'name' => $payload['Name'] ?? '',
                'email' => $payload['Email'] ?? '',
                'phone' => $payload['Phone'] ?? '',
            ]);
        } elseif ($cardType === 'document') {
            // שמירת מסמך חדש
            Document::create([
                'sumit_id' => $cardId,
                'number' => $payload['Number'] ?? '',
                'amount' => $payload['Amount'] ?? 0,
            ]);
        }

        // סימון כמעובד
        $webhook->markAsProcessed('Successfully synced');
    }

    protected function handleCardUpdated(SumitWebhook $webhook): void
    {
        // עדכון כרטיס קיים
        $cardType = $webhook->card_type;
        $cardId = $webhook->card_id;

        if ($cardType === 'customer') {
            Customer::where('sumit_id', $cardId)->update([
                'name' => $webhook->payload['Name'] ?? '',
                'email' => $webhook->payload['Email'] ?? '',
            ]);
        }

        $webhook->markAsProcessed('Successfully updated');
    }

    protected function handleCardDeleted(SumitWebhook $webhook): void
    {
        // מחיקת כרטיס
        $cardType = $webhook->card_type;
        $cardId = $webhook->card_id;

        if ($cardType === 'customer') {
            Customer::where('sumit_id', $cardId)->delete();
        }

        $webhook->markAsProcessed('Successfully deleted');
    }

    protected function handleCardArchived(SumitWebhook $webhook): void
    {
        // סימון כרטיס כמאורכב
        $cardType = $webhook->card_type;
        $cardId = $webhook->card_id;

        if ($cardType === 'customer') {
            Customer::where('sumit_id', $cardId)
                ->update(['archived' => true]);
        }

        $webhook->markAsProcessed('Successfully archived');
    }
}
```

### שימוש ב-Eloquent

[](#שימוש-ב-eloquent)

```
use OfficeGuy\LaravelSumitGateway\Models\SumitWebhook;

// קבלת webhooks שטרם טופלו
$pending = SumitWebhook::received()->get();

// קבלת webhooks לפי סוג אירוע
$createdCards = SumitWebhook::ofType('card_created')->get();

// קבלת webhooks לפי סוג כרטיס
$customerWebhooks = SumitWebhook::ofCardType('customer')->get();

// קבלת webhooks שנכשלו
$failed = SumitWebhook::failed()->get();

// קבלת webhooks של לקוח ספציפי
$customerWebhooks = SumitWebhook::forCustomer('CUST123')->get();

// סימון webhook כמעובד
$webhook->markAsProcessed('Synced to CRM', [
    'transaction_id' => $transaction->id,
]);

// סימון webhook כנכשל
$webhook->markAsFailed('API error: 500');

// סימון webhook כמתעלם
$webhook->markAsIgnored('Duplicate webhook');
```

### התמודדות עם ניסיונות חוזרים מ-SUMIT

[](#התמודדות-עם-ניסיונות-חוזרים-מ-sumit)

SUMIT מבצעת ניסיונות חוזרים אוטומטיים:

1. **Timeout:** המערכת ממתינה 10 שניות לתשובה
2. **Retry:** אם אין תשובה, ממתינה 30 שניות ומנסה שוב
3. **Max Retries:** לאחר 5 ניסיונות כושלים, הטריגר מושהה
4. **Resume:** כשהטריגר מופעל מחדש, כל הפעולות שהצטברו נשלחות

**המלצות:**

```
// מומלץ: עיבוד אסינכרוני
public function handle(Request $request): JsonResponse
{
    // שמירה מהירה של ה-webhook
    $webhook = SumitWebhook::createFromRequest(...);

    // דחיית העיבוד ל-queue
    ProcessSumitWebhookJob::dispatch($webhook);

    // החזרת תשובה מיידית (תוך 10 שניות!)
    return response()->json(['success' => true], 200);
}
```

### דוגמאות שימוש נפוצות

[](#דוגמאות-שימוש-נפוצות)

#### סנכרון לקוחות

[](#סנכרון-לקוחות)

```
// app/Jobs/SyncCustomerFromSumit.php
public function handle(): void
{
    $webhook = $this->webhook;

    if ($webhook->card_type !== 'customer') {
        $webhook->markAsIgnored('Not a customer card');
        return;
    }

    $payload = $webhook->payload;

    Customer::updateOrCreate(
        ['sumit_id' => $webhook->card_id],
        [
            'name' => $payload['Name'] ?? '',
            'email' => $payload['Email'] ?? '',
            'phone' => $payload['Phone'] ?? '',
            'address' => $payload['Address'] ?? '',
        ]
    );

    $webhook->markAsProcessed('Customer synced');
}
```

#### עדכון מלאי

[](#עדכון-מלאי)

```
// app/Jobs/SyncInventoryFromSumit.php
public function handle(): void
{
    $webhook = $this->webhook;

    if ($webhook->card_type !== 'item') {
        $webhook->markAsIgnored('Not an item card');
        return;
    }

    $payload = $webhook->payload;

    Product::updateOrCreate(
        ['sumit_sku' => $payload['SKU'] ?? $webhook->card_id],
        [
            'name' => $payload['Name'] ?? '',
            'price' => $payload['Price'] ?? 0,
            'stock' => $payload['Stock'] ?? 0,
        ]
    );

    $webhook->markAsProcessed('Inventory synced');
}
```

#### התראה על מסמך חדש

[](#התראה-על-מסמך-חדש)

```
// app/Jobs/NotifyNewDocument.php
public function handle(): void
{
    $webhook = $this->webhook;

    if ($webhook->card_type !== 'document') {
        $webhook->markAsIgnored('Not a document');
        return;
    }

    $payload = $webhook->payload;

    // שליחת התראה לצוות
    Notification::route('slack', config('services.slack.webhook'))
        ->notify(new NewDocumentFromSumit([
            'document_number' => $payload['Number'] ?? '',
            'amount' => $payload['Amount'] ?? 0,
            'customer' => $payload['CustomerName'] ?? '',
        ]));

    $webhook->markAsProcessed('Notification sent');
}
```

---

מיגרציות נתונים
---------------

[](#מיגרציות-נתונים)

### טבלאות

[](#טבלאות)

טבלהתיאור`officeguy_transactions`טרנזקציות תשלום`officeguy_tokens`כרטיסי אשראי שמורים`officeguy_documents`חשבוניות וקבלות`officeguy_settings`הגדרות מערכת`vendor_credentials`credentials לספקים`subscriptions`מנויים`officeguy_webhook_events`אירועי Webhook (יוצאים)`officeguy_sumit_webhooks`Webhooks מ-SUMIT (נכנסים)המיגרציות נטענות אוטומטית מהחבילה. להעתקה מקומית:

```
php artisan vendor:publish --tag=officeguy-migrations
```

---

בדיקות
------

[](#בדיקות)

- phpunit / orchestra testbench מומלצים
- החבילה כוללת בסיס מיגרציות
- יש להגדיר מודל Order דמה ל-Payable

**הרצת בדיקות:**

```
composer test
```

---

קבצים לפרסום (Publishable Assets)
---------------------------------

[](#קבצים-לפרסום-publishable-assets)

החבילה מציעה מספר קבצים לפרסום (publish) להתאמה אישית. להלן פירוט כל קובץ, מה הוא מכיל, ומתי כדאי להשתמש בו.

### פקודת Publish כללית

[](#פקודת-publish-כללית)

```
# פרסום כל הקבצים בבת אחת
php artisan vendor:publish --provider="OfficeGuy\LaravelSumitGateway\OfficeGuyServiceProvider"

# או פרסום קבצים ספציפיים לפי תגית (tag)
php artisan vendor:publish --tag=
```

### 1. קונפיגורציה (`--tag=officeguy-config`)

[](#1-קונפיגורציה---tagofficeguy-config)

```
php artisan vendor:publish --tag=officeguy-config
```

**מיקום:** `config/officeguy.php`

**מה מכיל:**

- הגדרות חברה (Company ID, API Keys)
- מצב PCI (no/redirect/yes)
- הגדרות תשלומים ותשלומים מחולקים (installments)
- הגדרות Bit
- הגדרות מסמכים
- הגדרות טוקנים
- הגדרות מנויים, תרומות, Multi-Vendor ו-Upsell
- הגדרות נתיבים (Routes)
- הגדרות מלאי
- הגדרות לוגים ו-SSL

**מתי להשתמש:**

- כאשר רוצים להגדיר ערכים קבועים שאינם משתנים מ-.env
- כאשר צריך להגדיר resolvers או callbacks מותאמים אישית (למשל `order.resolver`, `stock.update_callback`)
- כאשר רוצים לשנות את רשימת המטבעות הנתמכים
- כאשר צריך להגדיר middleware מותאם אישית לנתיבים

**דוגמה להתאמה אישית:**

```
// config/officeguy.php
return [
    'order' => [
        'resolver' => fn($id) => \App\Models\Order::with(['items', 'fees', 'customer'])->find($id),
    ],
    'stock' => [
        'update_callback' => fn(array $stockItem) => \App\Services\InventoryService::updateStock($stockItem),
    ],
    'multivendor' => [
        'enabled' => true,
        'vendor_resolver' => fn(array $item) => \App\Models\Vendor::find($item['vendor_id']),
    ],
];
```

### 2. מיגרציות (`--tag=officeguy-migrations`)

[](#2-מיגרציות---tagofficeguy-migrations)

```
php artisan vendor:publish --tag=officeguy-migrations
```

**מיקום:** `database/migrations/`

**מה מכיל:**

- `create_officeguy_transactions_table` - טבלת טרנזקציות
- `create_officeguy_tokens_table` - טבלת טוקנים (כרטיסי אשראי שמורים)
- `create_officeguy_documents_table` - טבלת מסמכים (חשבוניות/קבלות)
- `create_officeguy_settings_table` - טבלת הגדרות
- `create_vendor_credentials_table` - טבלת credentials לספקים (Multi-Vendor)
- `create_subscriptions_table` - טבלת מנויים
- `add_donation_and_vendor_fields` - שדות נוספים לתרומות וספקים

**מתי להשתמש:**

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

**הערה חשובה:** לאחר פרסום המיגרציות, החבילה תמשיך לטעון את המיגרציות שלה מ-`vendor/`. כדי למנוע כפילויות, ודאו שאתם לא מריצים את אותן מיגרציות פעמיים.

### 3. תצוגות (`--tag=officeguy-views`)

[](#3-תצוגות---tagofficeguy-views)

```
php artisan vendor:publish --tag=officeguy-views
```

**מיקום:** `resources/views/vendor/officeguy/`

**מה מכיל:**

- **`components/payment-form.blade.php`** - טופס תשלום עם:
    - שדות כרטיס אשראי (מספר, תוקף, CVV, ת.ז.)
    - בחירת אמצעי תשלום שמור (טוקן)
    - בחירת מספר תשלומים
    - תמיכה ב-RTL וולידציה צד-לקוח עם Alpine.js
- **`pages/checkout.blade.php`** - עמוד תשלום ציבורי מלא עם:
    - תצוגת סיכום הזמנה
    - פרטי לקוח
    - בחירת אמצעי תשלום (כרטיס/Bit)
    - תמיכה בתשלומים
    - עיצוב מודרני עם Tailwind CSS
    - תמיכה מלאה ב-RTL
- **`filament/pages/officeguy-settings.blade.php`** - עמוד הגדרות ב-Filament Admin
- **`filament/client/payment-methods/hosted-token-form.blade.php`** - טופס ניהול אמצעי תשלום ללקוח

**מתי להשתמש:**

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

**דוגמה להתאמת טופס תשלום:**

```
{{-- resources/views/vendor/officeguy/components/payment-form.blade.php --}}

    {{-- הוספת לוגו חברה --}}

    {{-- שאר הטופס... --}}

```

### טבלת סיכום

[](#טבלת-סיכום)

תגיתמיקום יעדשימוש עיקרי`officeguy-config``config/officeguy.php`הגדרות API, תשלומים, resolvers`officeguy-migrations``database/migrations/`התאמת מבנה מסד נתונים`officeguy-views``resources/views/vendor/officeguy/`התאמת עיצוב וממשק משתמש### העתקה סלקטיבית

[](#העתקה-סלקטיבית)

ניתן לפרסם מספר תגיות בבת אחת:

```
# פרסום קונפיג ותצוגות בלבד
php artisan vendor:publish --tag=officeguy-config --tag=officeguy-views
```

עמוד תשלום ציבורי (Public Checkout Page)
----------------------------------------

[](#עמוד-תשלום-ציבורי-public-checkout-page)

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

### הפעלה

[](#הפעלה)

ניתן להפעיל את עמוד התשלום הציבורי בשתי דרכים:

**1. דרך Admin Panel (מומלץ):**

גשו לעמוד ההגדרות ב-Filament Admin Panel:

- נווטו ל-**SUMIT Gateway** &gt; **Gateway Settings**
- מצאו את הסעיף **"Public Checkout Page"**
- הפעילו את **"Enable Public Checkout"**
- הגדירו את **"Payable Model Class"** עם שם המודל המלא (לדוגמה: `App\Models\Order`)
- ניתן גם להגדיר נתיב מותאם אישית

**2. דרך קובץ .env:**

```
OFFICEGUY_ENABLE_PUBLIC_CHECKOUT=true
OFFICEGUY_ORDER_MODEL=App\Models\Order
```

### שימוש

[](#שימוש)

לאחר ההפעלה, ניתן לגשת לעמוד התשלום בכתובת:

```
GET /officeguy/checkout/{id}

```

כאשר `{id}` הוא המזהה של המודל ה-Payable (למשל מזהה הזמנה).

### דוגמה - יצירת קישור תשלום

[](#דוגמה---יצירת-קישור-תשלום)

```
// יצירת קישור תשלום להזמנה
$order = Order::find(123);
$checkoutUrl = route('officeguy.public.checkout', ['id' => $order->id]);

// שליחת הקישור ללקוח
Mail::to($order->customer_email)->send(new PaymentLinkEmail($checkoutUrl));
```

### התאמה אישית של המודל

[](#התאמה-אישית-של-המודל)

יש שתי דרכים לחבר את המודל שלכם לעמוד התשלום:

**אפשרות 1: מיפוי שדות מ-Admin Panel (ללא שינוי קוד)**

ניתן לחבר כל מודל קיים **מבלי לשנות את הקוד שלו**. פשוט הגדירו את מיפוי השדות ב-Admin Panel:

1. גשו ל-**SUMIT Gateway** &gt; **Gateway Settings** &gt; **Field Mapping**
2. הזינו את שמות השדות במודל שלכם:
    - **Amount Field** - שדה הסכום (לדוגמה: `total`, `price`, `amount`)
    - **Currency Field** - שדה המטבע (לדוגמה: `currency`) או השאירו ריק עבור ILS
    - **Customer Name Field** - שדה שם הלקוח
    - **Customer Email Field** - שדה האימייל
    - **Customer Phone Field** - שדה הטלפון
    - **Description Field** - שדה תיאור הפריט

המערכת תעטוף אוטומטית את המודל שלכם ותמפה את השדות.

**אפשרות 2: מימוש ממשק Payable (למודלים מורכבים)**

```
use OfficeGuy\LaravelSumitGateway\Contracts\Payable;
use OfficeGuy\LaravelSumitGateway\Support\Traits\PayableAdapter;

class Order extends Model implements Payable
{
    use PayableAdapter;

    // או מימוש ידני של המתודות
}
```

### התאמת העיצוב

[](#התאמת-העיצוב)

פרסמו את התצוגות והתאימו את `pages/checkout.blade.php`:

```
php artisan vendor:publish --tag=officeguy-views
```

לאחר מכן ערכו את הקובץ `resources/views/vendor/officeguy/pages/checkout.blade.php` להתאמה לעיצוב האתר שלכם.

### משתנים זמינים בתצוגה

[](#משתנים-זמינים-בתצוגה)

משתנהתיאור`$payable`אובייקט ה-Payable (הזמנה/מוצר)`$settings`הגדרות שער התשלום`$maxPayments`מספר תשלומים מקסימלי`$bitEnabled`האם Bit מופעל`$supportTokens`האם שמירת כרטיסים מופעלת`$savedTokens`אוסף כרטיסים שמורים (למשתמש מחובר)`$currency`קוד מטבע (ILS, USD וכו')`$currencySymbol`סימן מטבע (₪, $ וכו')`$checkoutUrl`כתובת לשליחת הטופס### Resolver מותאם אישית

[](#resolver-מותאם-אישית)

ניתן להגדיר resolver מותאם אישית בקונפיגורציה:

```
// config/officeguy.php
'order' => [
    'resolver' => fn($id) => \App\Models\Product::with('prices')->find($id),
],
```

רישיון
------

[](#רישיון)

MIT

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance84

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 69.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Recently: every ~7 days

Total

95

Last Release

68d ago

Major Versions

v1.21.6 → v2.0.02026-01-18

v2.7.0 → v3.0.02026-03-02

v3.0.2 → 5.0.0-rc12026-03-03

v3.0.3 → 5.0.0-rc32026-03-31

PHP version history (2 changes)v1.0.0PHP ^8.2

5.0.0-rc2PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/127d9d84318cddc32aa5b44640b8f431b89793d11eddf26c55938e8c0b87a217?d=identicon)[NMDIGITALHUB](/maintainers/NMDIGITALHUB)

---

Top Contributors

[![nm-digitalhub](https://avatars.githubusercontent.com/u/211350234?v=4)](https://github.com/nm-digitalhub "nm-digitalhub (215 commits)")[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (95 commits)")

---

Tags

laravellaravel 12paymentgatewaycredit-cardbitIsraelsumitofficeguylaravel-13

###  Code Quality

TestsPHPUnit

Static AnalysisRector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/officeguy-laravel-sumit-gateway/health.svg)

```
[![Health](https://phpackages.com/badges/officeguy-laravel-sumit-gateway/health.svg)](https://phpackages.com/packages/officeguy-laravel-sumit-gateway)
```

###  Alternatives

[statamic/cms

The Statamic CMS Core Package

4.8k3.6M993](/packages/statamic-cms)[unopim/unopim

UnoPim Laravel PIM

10.5k2.4k](/packages/unopim-unopim)[sebdesign/laravel-viva-payments

A Laravel package for integrating the Viva Payments gateway

4851.0k](/packages/sebdesign-laravel-viva-payments)[codewithdennis/larament

Larament is a time-saving starter kit to quickly launch Laravel 13.x projects. It includes FilamentPHP 5.x pre-installed and configured, along with additional tools and features to streamline your development workflow.

3991.8k](/packages/codewithdennis-larament)[ercogx/laravel-filament-starter-kit

This is a Filament v5 Starter Kit for Laravel 13, designed to accelerate the development of Filament-powered applications.

461.7k](/packages/ercogx-laravel-filament-starter-kit)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
