WP Manifestindependent plugin directory
manifest / ecommerce / sales-assistant-wp

Bento — لیست سفارشات پیشرفته

نمایش تصویر، نام، رنگ، پاپ‌آپ جزئیات و تغییر وضعیت مستقیم در لیست سفارشات ووکامرس.

by آٰرش فدائی · github.com/arashfadaee/sales-assistant-wp

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/arashfadaee/sales-assistant-wp/archive/refs/heads/main.zip

Readme

Bento — لیست سفارشات پیشرفته

افزونه اختصاصی ووکامرس برای فروشگاه بنتو آبجکت (bentoobject.com).

نسخه فعلی هسته: 1.5.0 · ماژول پیشنهاد پکیج: 1.2.0 · نویسنده: آٰرش فدائی


خلاصه یک‌خطی

این افزونه سه کار اصلی را برای عملیات فروشگاه انجام می‌دهد:

  1. مدیریت سریع سفارشات در ادمین — تصویر، رنگ، جزئیات، تغییر وضعیت، چاپ لیبل و ویجت داشبورد
  2. زمان ساخت + پیامک sms.ir — محاسبه روز آماده شدن و ارسال خودکار هنگام ورود به «در حال انجام»
  3. پیشنهاد پکیج در Checkout — کراس‌سل تیشو پاد ↔ آباژور با تخفیف ۱:۱ و شمارش‌معکوس

پیش‌نیازها

مورد حداقل
WordPress 6.4+
PHP 7.4+
WooCommerce 8.2+ (تست‌شده تا 10.1)
سازگاری HPOS (custom_order_tables) و Cart/Checkout Blocks اعلام شده‌اند

پیشنهاد پکیج Checkout فعلاً فقط روی Classic Checkout رندر می‌شود. تخفیف کارتی (fee) مستقل از UI است و روی سبد اعمال می‌شود.


نصب

  1. پوشه افزونه را در wp-content/plugins/ قرار دهید (یا از همین ریپو به‌صورت مستقیم استفاده کنید).
  2. از افزونه‌ها در وردپرس فعال کنید.
  3. مطمئن شوید ووکامرس فعال است؛ در غیر این صورت کلاس اصلی boot نمی‌شود.

فایل اصلی افزونه: wc-enhanced-orders-list.php


ساختار فایل‌ها

hamid/
├── wc-enhanced-orders-list.php          # هسته اصلی (Singleton) — سفارشات، لیبل، SMS، UI ادمین
├── includes/
│   └── class-bento-bundle-offer.php     # ماژول پیشنهاد پکیج Checkout + تخفیف ۱:۱
├── assets/
│   ├── bento-bundle-offer.js            # Countdown + AJAX افزودن به سبد
│   ├── bento-bundle-offer.css           # استایل باکس پیشنهاد (RTL)
│   ├── bento-brand-logo.png
│   ├── tissue-pod-icon.png
│   ├── tissue-pod-wordmark.png
│   └── …                                # دارایی‌های برند برای لیبل چاپ
├── .gitignore
└── README.md

CSS/JS لیست سفارشات داخل خود wc-enhanced-orders-list.php با print_css() / print_js() تزریق می‌شوند (نه فایل جدا).


معماری کلی

                    ┌─────────────────────────────────────┐
                    │   WordPress / WooCommerce hooks     │
                    └─────────────────┬───────────────────┘
                                      │
              ┌───────────────────────┴───────────────────────┐
              │                                               │
              ▼                                               ▼
┌─────────────────────────────┐               ┌──────────────────────────────┐
│ Bento_WC_Enhanced_Orders_List│               │   Bento_WC_Bundle_Offer      │
│ (Singleton · v1.5.0)         │──boot_bundle─▶│   (Singleton · v1.0.0)       │
│                              │               │                              │
│ • منوی «دستیار فروش»         │               │ • ساب‌منوی «پیشنهاد پکیج»    │
│ • ستون‌های HPOS / Legacy     │               │ • UI Classic Checkout        │
│ • AJAX جزئیات / وضعیت        │               │ • AJAX add-to-cart           │
│ • چاپ لیبل پستی              │               │ • Fee تخفیف ۱:۱              │
│ • sms.ir + روز ساخت          │               │ • قوانین اگر→آنگاه محصول/رنگ │
│ • ویجت داشبورد               │               │ • Session countdown          │
└─────────────────────────────┘               └──────────────────────────────┘

الگوی طراحی

  • Singleton برای هر دو کلاس (instance() + فلگ $booted)
  • Separation of concerns: منطق سفارشات از منطق Checkout جداست؛ ماژول پکیج فقط از boot_bundle_offer() لود می‌شود
  • Cache در حافظه درخواست: $lines_cache، $product_cache برای جلوگیری از query تکراری
  • Hook-agnostic payloads در Bundle Offer (get_offer_state, calculate_discount_amount) تا بعداً بتوان Blocks را بدون بازنویسی منطق وصل کرد
  • اعلام سازگاری WC روی before_woocommerce_init برای HPOS و Blocks

چرخه Boot

before_woocommerce_init  → declare_wc_feature_compatibility()
woocommerce_init / init / admin_init → boot() → init()
                                              → boot_bundle_offer()

ماژول ۱ — لیست و عملیات سفارشات

کلاس: Bento_WC_Enhanced_Orders_List

منوی ادمین

صفحه slug قابلیت
دستیار فروش bento-site-orders لیست کارت‌محور سفارشی (جستجو، فیلتر وضعیت، صفحه‌بندی)
پیامک sms.ir bento-site-orders-settings API کلید، templateId، روز ساخت Tissue/YoYo
پیشنهاد پکیج bento-bundle-offer (از ماژول دوم)

منوی «دستیار فروش» با menu_order به بالای منوی ادمین منتقل می‌شود.

ستون‌های لیست ووکامرس

روی هر دو مسیر Legacy CPT و HPOS کار می‌کند:

ستون کلید محتوا
محصول bento_product تصویر بندانگشتی + نام + تعداد
رنگ bento_color چیپ رنگی با hex تقریبی
عملیات سریع bento_actions تغییر وضعیت AJAX، مودال جزئیات، لینک چاپ لیبل

صفحه سفارشی «دستیار فروش»

  • کارت هر سفارش: شماره، وضعیت، تاریخ، محصول/رنگ، مشتری، موبایل، شهر/استان، مبلغ، اکشن‌ها
  • جستجو بر اساس شماره سفارش، نام، ایمیل، یا موبایل (field_query روی billing_phone)
  • فیلتر وضعیت و per_page (۱۰ / ۱۲ / ۲۰ / ۵۰)

AJAX

Action نقش
bento_get_order_details payload کامل مشتری، آدرس، آیتم‌ها، پرداخت، روز ساخت، لینک چاپ
bento_update_order_status تغییر وضعیت سفارش بدون باز کردن صفحه ویرایش

Nonce مشترک: bento_orders_list

ویجت داشبورد

ویجت bento_site_orders_widget شش سفارش اخیر را نشان می‌دهد (جزئیات + لیبل) و به بالای داشبورد پین می‌شود.


ماژول ۲ — چاپ لیبل پستی

  • Endpoint: admin-post.php?action=bento_print_label&order_id=… با nonce اختصاصی هر سفارش
  • برای هر ترکیب محصول/رنگ یک کپی لیبل ساخته می‌شود
  • شامل: فرستنده (قابل فیلتر)، گیرنده، آدرس (حداکثر ۳ خط)، کدپستی (خارج تهران)، QR، تاریخ جلالی، کد ملی سفارش (در صورت وجود)، برندینگ Tissue Pod / Bento
  • ادیتور فیلدهای لیبل در صفحه چاپ (JS داخلی) قبل از چاپ مرورگر

فیلتر پروفایل فرستنده:

apply_filters( 'bento_orders_label_sender', $defaults );

ماژول ۳ — روز ساخت و پیامک sms.ir

منطق روز آماده شدن

  • هر خط سفارش یک kind می‌گیرد: tissue | yoyo | object
  • تشخیص kind از طریق:
    1. فیلتر bento_production_product_ids (پیش‌فرض: 119 → tissue, 1203 → yoyo)
    2. متای _english_name یا نام محصول (کلمات tissue / تیشو / دستمال / yoyo / آباژ)
  • روز پیش‌فرض از آپشن‌ها: Tissue = ۵، YoYo = ۳
  • override در سطح محصول با متای _bento_production_days
  • روزها جمع نمی‌شوند؛ بیشترین lead time سفارش ذخیره می‌شود در متای _bento_ready_days
  • فیلتر نهایی: bento_order_ready_days

Persist روی:

  • woocommerce_checkout_order_processed
  • woocommerce_store_api_checkout_order_processed
  • woocommerce_new_order
  • woocommerce_order_status_changed

ارسال پیامک

  • تریگر: woocommerce_order_status_processing
  • یک‌بار در هر سفارش (متای _bento_smsir_sent)
  • API: https://api.sms.ir/v1/send/verify
  • نرمال‌سازی موبایل ایران (09xxxxxxxxx) با پشتیبانی ارقام فارسی/عربی

متغیرهای قالب پیشنهادی:

name معنی
B_FIRST_NAME نام صورتحساب
B_LAST_NAME نام خانوادگی
ORDER_ID شماره سفارش
BENTO_READY_DAYS روز ساخت (ارقام فارسی)
ALL_ITEMS خلاصه آیتم‌ها با رنگ و تعداد
PRICE مبلغ سفارش

آپشن‌های تنظیمات:

  • bento_smsir_api_key
  • bento_smsir_template_id
  • bento_production_days_tissue
  • bento_production_days_yoyo

ماژول ۴ — پیشنهاد پکیج Checkout

کلاس: Bento_WC_Bundle_Offer · Offer ID: tissue_abajour · نسخه ماژول: 1.2.0

ایده کسب‌وکار

اگر مشتری فقط یکی از دو گروه تیشو پاد یا آباژور را در سبد داشته باشد، بر اساس قوانین شرطی ادمین (محصول+رنگ مبدأ → محصول+رنگ پیشنهادی) پیشنهاد می‌شود. با افزودن جفت، حداکثر روی یک جفت تخفیف درصدی اعمال می‌شود (MAX_ELIGIBLE_PAIRS = 1).

حالت‌های UI (get_offer_state)

mode معنی
hidden پیشنهاد نشان داده نمی‌شود
offer پیشنهاد فعال + countdown
expired مهلت تمام شده
bundle_active هر دو گروه در سبد؛ تخفیف اعمال شده

تخفیف

discount = (unit_tissue + unit_abajour) × 1 × (percent / 100)

به‌صورت negative fee روی سبد:

«تخفیف پکیج تیشو پاد + آباژور»

درصد پیش‌فرض: ۷٪ (قابل تنظیم ۰–۱۰۰)

گروه‌بندی سبد از tissue_ids و abajour_ids است (فقط برای تشخیص گروه و تخفیف).

پیشنهاد با قوانین شرطی (بدون هوشمندی)

ادمین چند قانون «اگر → آنگاه» تعریف می‌کند. ترتیب مهم است؛ اولین قانون منطبق اجرا می‌شود.

فیلد قانون معنی
when اگر این محصول/variation (رنگ) در سبد باشد
then این محصول/variation را پیشنهاد بده

مثال:

  • اگر آباژور آبی → پیشنهاد تیشو پاد آبی

  • اگر آباژور صورتی → پیشنهاد تیشو پاد صورتی

  • اگر تیشو پاد سبز → پیشنهاد آباژور سبز

  • جستجو از woocommerce_json_search_products_and_variations است تا بتوان variation رنگ را مستقیم انتخاب کرد

  • انتخاب محصول والد متغیر (بدون variation) رد می‌شود

  • قوانین ناقص یا تکراری هنگام ذخیره حذف می‌شوند (حداکثر ۴۰ قانون)

  • اگر هیچ قانونی منطبق نباشد، باکس پیشنهاد مخفی می‌ماند (hidden)

Countdown

  • مدت قابل انتخاب: ۳۰ / ۶۰ / ۹۰ / ۱۲۰ دقیقه (پیش‌فرض ۹۰)
  • زمان شروع در WC Session: bento_bundle_offer_started_at
  • کلاینت با localStorage همگام می‌شود؛ باقی‌مانده = min(سرور، کلاینت)
  • بعد از انقضا CTA غیرفعال و mode = expired

Frontend

  • هوک پیش‌فرض رندر: woocommerce_review_order_before_payment
  • قابل تغییر با فیلتر bento_bundle_offer_checkout_hook
  • AJAX: bento_bundle_add (لاگین و مهمان)
  • اسکریپت/استایل فقط روی Classic Checkout و وقتی فیچر + باکس پیشنهاد فعال باشند

آپشن

کلید: bento_bundle_offer

enabled, checkout_offer, discount_percent, countdown_minutes,
tissue_ids[], abajour_ids[],
rules[]: { when, then },
offer_title, cta_text

فیلترها و نقاط توسعه

فیلتر / ثابت کاربرد
bento_order_ready_days تغییر روز ساخت نهایی سفارش
bento_production_days نقشه روز پیش‌فرض kindها
bento_production_product_ids نگاشت product_id → kind
bento_orders_label_sender اطلاعات فرستنده لیبل
bento_bundle_offer_checkout_hook محل رندر باکس پیشنهاد

متاهای محصول/سفارش مفید:

Meta محل نقش
_bento_ready_days سفارش روز ساخت محاسبه‌شده
_bento_smsir_sent سفارش جلوگیری از ارسال مجدد SMS
_bento_production_days محصول override روز ساخت
_english_name محصول کمک به تشخیص kind

امنیت و دسترسی

  • Capability: edit_shop_orders برای لیست/لیبل/جزئیات؛ manage_woocommerce برای تنظیمات
  • Nonce روی همه فرم‌های ادمین، AJAX و چاپ لیبل
  • Sanitize/escape خروجی‌ها؛ API key پیامک به‌صورت password ذخیره و فقط در صورت ورود مقدار جدید به‌روز می‌شود
  • درخواست‌های AJAX افزودن به سبد، product/variation پیشنهادی را با state سرور تطبیق می‌دهند تا دستکاری POST بی‌اثر باشد

جریان‌های اصلی (Flow)

سفارش جدید → پیامک

Checkout / New Order
    → persist_order_ready_days()  [_bento_ready_days]
Status → processing
    → maybe_send_production_sms()
        → sms.ir verify template
        → _bento_smsir_sent + order note

اپراتور در ادمین

دستیار فروش / لیست WC / داشبورد
    → دیدن محصول و رنگ
    → تغییر وضعیت (AJAX)
    → مودال جزئیات (AJAX)
    → چاپ لیبل (admin-post + nonce)

پیشنهاد پکیج در Checkout

سبد فقط Tissue یا فقط Abajour
    → resolve_rule_suggestion() (اولین قانون منطبق)
    → get_offer_state() = offer
    → رندر باکس + countdown
    → AJAX add complementary product
    → cart has both groups
    → apply_bundle_fee() (1 pair only)
    → mode = bundle_active

تنظیمات پیشنهادی راه‌اندازی

  1. دستیار فروش → پیامک sms.ir
    • API Key و Template ID را از پنل sms.ir وارد کنید
    • متغیرهای قالب را دقیقاً با نام‌های جدول بالا بسازید
    • روز ساخت Tissue / YoYo را تنظیم کنید
  2. دستیار فروش → پیشنهاد پکیج
    • محصولات تیشو پاد و آباژور را برای گروه‌بندی/تخفیف انتخاب کنید
    • در بخش قوانین، برای هر رنگ یک شرط «اگر → آنگاه» بسازید
    • درصد تخفیف و مدت countdown را مشخص کنید
  3. سفارش تستی بسازید و مسیر processing + Classic Checkout را یک‌بار بررسی کنید

محدودیت‌ها و نکات فنی

  • فایل هسته بزرگ است (~۳۷۰۰ خط) و CSS/JS ادمین را inline نگه می‌دارد؛ ماژول Bundle جداگانه و سبک‌تر است
  • UI پیشنهاد Checkout برای Blocks هنوز پیاده نشده؛ فقط اعلام سازگاری و payloadهای قابل‌استفاده مجدد وجود دارد
  • تشخیص kind در لیست سفارشات تا حدی به IDهای ثابت فروشگاه و نام محصول وابسته است (با فیلتر قابل تغییر)
  • QR لیبل از سرویس خارجی api.qrserver.com ساخته می‌شود
  • Text domain: bento-orders-list

نقشه راه پیشنهادی (خارج از کد فعلی)

  • استخراج CSS/JS ادمین به فایل‌های استاتیک نسخه‌دار
  • یکپارچه‌سازی پیشنهاد پکیج با Checkout Blocks از روی get_offer_state
  • تست‌های واحد برای compute_pair_discount و scoring رنگ
  • تنظیم‌پذیر کردن پروفایل فرستنده لیبل از UI به‌جای فقط فیلتر

لایسنس و مالکیت

افزونه اختصاصی فروشگاه بنتو آبجکت است و برای استفاده داخلی/سفارشی نوشته شده؛ انتشار عمومی یا لایسنس باز در این ریپو تعریف نشده است.

Read the full README on GitHub →