مجله ایرانیکاسرورآموزش سرور، هاست، وردپرس و شبکه
آموزشی

مدیریت چند انبار در ووکامرس؛ کنترل موجودی و تخصیص هوشمند سفارش‌ها

اگر یک فروشگاه ووکامرسی فقط یک محل نگهداری کالا داشته باشد، عدد موجودی خود WooCommerce معمولاً کافی است. اما وقتی یک محصول هم‌زمان در انبار تهران، شیراز و مشهد موجود باشد، دیگر دانستن اینکه…

مدیریت چند انبار در ووکامرس؛ کنترل موجودی و تخصیص هوشمند سفارش‌ها
خلاصه سریع این آموزش

اگر یک فروشگاه ووکامرسی فقط یک محل نگهداری کالا داشته باشد، عدد موجودی خود WooCommerce معمولاً کافی است. اما وقتی یک محصول هم‌زمان در انبار تهران، شیراز و مشهد موجود…

۱۷ دقیقه مطالعه ۰ دیدگاه ۱۹ مهر ۱۴۰۵ آخرین به‌روزرسانی

اگر یک فروشگاه ووکامرسی فقط یک محل نگهداری کالا داشته باشد، عدد موجودی خود WooCommerce معمولاً کافی است. اما وقتی یک محصول هم‌زمان در انبار تهران، شیراز و مشهد موجود باشد، دیگر دانستن اینکه «این محصول ۲۷ عدد موجودی دارد» کافی نیست؛ باید بدانیم این ۲۷ عدد دقیقاً کجا هستند، سفارش از کدام انبار ارسال شود، چه مقدار در هر محل رزرو شده و انتقال کالا بین دو انبار چه اثری روی موجودی قابل فروش دارد.

این مقاله دقیقاً برای همین سناریو است. یک معماری چندانباره برای WooCommerce طراحی می‌کنیم که موجودی هر انبار را مستقل نگه می‌دارد، Stock کل فروشگاه را با ووکامرس هماهنگ می‌کند، هنگام ثبت سفارش یک یا چند انبار را به اقلام سفارش اختصاص می‌دهد، انتقال بین انبارها را کنترل می‌کند و در لغو یا مرجوعی نیز می‌داند کالا باید به کدام محل برگردد.

📌 نتیجه نهایی: WooCommerce همچنان یک موجودی کل قابل اعتماد برای کنترل فروش دارد، اما جزئیات موجودی در سطح انبار داخل لایه اختصاصی نگهداری می‌شود. بنابراین هم Checkout ووکامرس درست کار می‌کند و هم مدیر فروشگاه می‌فهمد هر واحد کالا در کدام انبار قرار دارد.

فهرست مطالب

آیا WooCommerce به‌صورت پیش‌فرض چند انبار دارد؟

هسته WooCommerce برای هر محصول یا Variation یک مقدار اصلی Stock Quantity نگه می‌دارد. یعنی می‌تواند بگوید یک کالا ۲۰ عدد موجود است، اما به‌صورت بومی نمی‌گوید ۸ عدد در تهران، ۷ عدد در مشهد و ۵ عدد در شیراز قرار دارد.

برای همین قابلیت چندمکانی معمولاً با افزونه تخصصی یا توسعه اختصاصی اضافه می‌شود. حتی افزونه‌های Multi Inventory موجود در Marketplace ووکامرس نیز یک لایه جدا برای Location، موجودی هر محل، اولویت انبار و تخصیص سفارش ایجاد می‌کنند.

چه چیزی در WooCommerce می‌ماند و چه چیزی را خودمان اضافه می‌کنیم؟
داده محل نگهداری کاربرد
موجودی کل محصول WooCommerce کنترل فروش، Checkout و Backorder
موجودی انبار تهران جدول اختصاصی Location Stock موجودی فیزیکی همان محل
رزرو هر انبار جدول Allocation/Reservation جلوگیری از اختصاص یک کالای واحد به دو سفارش
انتقال بین انبارها جدول Transfer ثبت خروج از مبدا و ورود به مقصد
انبار تخصیص‌یافته سفارش Allocation مشخص‌کردن محل آماده‌سازی و ارسال کالا

معماری پیشنهادی چند انبار

اصل مهم این معماری این است که دو «منبع حقیقت» برای یک عدد نداشته باشیم. موجودی هر انبار در جدول چندانباره منبع اصلی جزئیات مکانی است و Stock خود WooCommerce برابر مجموع موجودی قابل فروش انبارهای فعال قرار می‌گیرد.

موجودی کل WooCommerce = مجموع موجودی قابل فروش تمام انبارهای فعال

اما یک نکته مهم وجود دارد: WooCommerce خودش هنگام Checkout موجودی سفارش‌های در جریان را به‌صورت سراسری رزرو می‌کند. رزرو اختصاصی ما فقط مشخص می‌کند همان سفارش از کدام انبار تأمین خواهد شد؛ بنابراین نباید رزرو مکانی را دوباره از Stock کل WooCommerce کم کنیم و باعث Double Reservation شویم.

⚠️ اشتباه خطرناک: اگر WooCommerce برای یک سفارش ۲ واحد را Hold کرده و سیستم چندانباره نیز همان ۲ واحد را از Stock کل کم کند، فروشگاه عملاً ۴ واحد را مسدود می‌کند. رزرو مکانی باید فقط روی موجودی همان Location اثر بگذارد؛ کاهش Stock کل هنگام فروش را به منطق خود WooCommerce بسپارید.

📌 قبل از توسعه روی فروشگاه اصلی

سیستم چندانباره مستقیماً روی فروش و Stock اثر می‌گذارد. قبل از ساخت جدول‌ها یا Hookهای جدید، از فروشگاه نسخه بازیابی داشته باشید. آموزش بکاپ خودکار وردپرس روی S3 برای ساخت یک نسخه خارج از هاست اصلی مفید است.

مرحله ۱: جدول انبارها را بسازید

هر انبار باید شناسه، کد یکتا، نام، اولویت و وضعیت فعال/غیرفعال داشته باشد. آدرس و اطلاعات تماس را هم می‌توان اضافه کرد، اما برای هسته موجودی همین اطلاعات کافی‌اند.

CREATE TABLE wp_iranica_warehouses (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    code VARCHAR(50) NOT NULL,
    name VARCHAR(190) NOT NULL,
    priority INT NOT NULL DEFAULT 100,
    is_active TINYINT(1) NOT NULL DEFAULT 1,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY uniq_code (code),
    KEY active_priority (is_active, priority)
) ENGINE=InnoDB;

برای نمونه می‌توانید کدهای کوتاهی مثل THR برای تهران، MHD برای مشهد و SHZ برای شیراز داشته باشید. کد بهتر است بعداً تغییر نکند، چون در API، گزارش و انتقال انبار به شناسه ثابت نیاز دارید.

مرحله ۲: موجودی هر محصول در هر انبار را جدا کنید

برای هر ترکیب «محصول + انبار» یک ردیف نگه می‌داریم. موجودی فیزیکی و موجودی رزروشده را از هم جدا می‌کنیم تا بدانیم چه مقدار کالا واقعاً روی قفسه است و چه مقدار آن قبلاً برای سفارش دیگری کنار گذاشته شده است.

CREATE TABLE wp_iranica_warehouse_stock (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    warehouse_id BIGINT UNSIGNED NOT NULL,
    product_id BIGINT UNSIGNED NOT NULL,
    stock_qty DECIMAL(20,4) NOT NULL DEFAULT 0,
    reserved_qty DECIMAL(20,4) NOT NULL DEFAULT 0,
    reorder_point DECIMAL(20,4) NULL,
    updated_at DATETIME NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY uniq_warehouse_product (
        warehouse_id,
        product_id
    ),
    KEY product_id (product_id),
    KEY warehouse_id (warehouse_id)
) ENGINE=InnoDB;

محصول متغیر را باید در سطح Variation ذخیره کنید؛ یعنی product_id بهتر است شناسه همان شیئی باشد که Stock واقعی را مدیریت می‌کند. برای تشخیص آن می‌توانید از متد get_stock_managed_by_id() استفاده کنید.

موجودی قابل فروش هر انبار را چگونه حساب کنیم؟

موجودی قابل تخصیص انبار = موجودی فیزیکی − موجودی رزروشده همان انبار

مثلاً اگر تهران ۱۲ عدد از یک محصول دارد و ۵ عدد آن برای سفارش‌های در جریان رزرو شده، فقط ۷ عدد برای تخصیص سفارش جدید آزاد است.

مرحله ۳: Stock کل WooCommerce را با مجموع انبارها هماهنگ کنید

هر بار که ورود کالا، خروج دستی، انتقال نهایی یا اصلاح موجودی انجام می‌شود، مجموع موجودی فیزیکی انبارهای فعال را محاسبه و Stock WooCommerce را با API رسمی خودش به‌روزرسانی کنید.

<?php

function iranica_sync_wc_stock_from_warehouses(
    int $product_id
) {
    global $wpdb;

    $product = wc_get_product( $product_id );

    if ( ! $product instanceof WC_Product ) {
        return new WP_Error(
            'product_not_found',
            'Product was not found.'
        );
    }

    $stock_owner_id =
        $product->get_stock_managed_by_id();

    $total = (float) $wpdb->get_var(
        $wpdb->prepare(
            "
            SELECT COALESCE(SUM(s.stock_qty), 0)
            FROM {$wpdb->prefix}iranica_warehouse_stock s
            INNER JOIN {$wpdb->prefix}iranica_warehouses w
                ON w.id = s.warehouse_id
            WHERE s.product_id = %d
              AND w.is_active = 1
            ",
            $stock_owner_id
        )
    );

    return wc_update_product_stock(
        $stock_owner_id,
        $total,
        'set'
    );
}

در این تابع عمداً reserved_qty را از مجموع Stock کل کم نکردیم؛ چون WooCommerce خودش رزرو سراسری Checkout را مدیریت می‌کند. Reserved مکانی برای انتخاب انبار است، نه جایگزین Hold Stock ووکامرس.

مرحله ۴: سفارش را به کدام انبار اختصاص بدهیم؟

انتخاب انبار فقط مسئله «کدام محل موجودی دارد؟» نیست. سیاست Fulfillment فروشگاه باید مشخص باشد.

چه سیاستی برای انتخاب انبار مناسب است؟
روش مزیت محدودیت
اولویت ثابت ساده و قابل پیش‌بینی ممکن است هزینه ارسال را بهینه نکند.
نزدیک‌ترین انبار کاهش مسیر حمل به نگاشت دقیق مقصد و Location نیاز دارد.
بیشترین موجودی احتمال Split Shipment کمتر می‌شود. ممکن است انبار دورتر انتخاب شود.
تقسیم بین چند انبار سفارش‌هایی را که یک انبار کامل ندارد نجات می‌دهد. هزینه ارسال و عملیات را پیچیده‌تر می‌کند.

برای نسخه اول، «اولویت انبار + موجودی کافی» معمولاً ساده‌ترین سیاست است. بعداً می‌توانید فاصله، منطقه ارسال، هزینه پیک یا SLA را وارد الگوریتم کنید.

رزرو انبار باید اتمیک باشد

فرض کنید فقط یک عدد کالا در تهران باقی مانده و دو مشتری هم‌زمان سفارش می‌دهند. اگر هر دو درخواست ابتدا موجودی را بخوانند و بعد رزرو کنند، ممکن است هر دو همان یک کالا را بگیرند.

راه امن‌تر این است که بررسی موجودی و افزایش Reserved در یک دستور شرطی دیتابیس انجام شود:

<?php

function iranica_reserve_location_stock(
    int $warehouse_id,
    int $product_id,
    float $qty
): bool {
    global $wpdb;

    if ( $qty <= 0 ) {
        return false;
    }

    $table =
        $wpdb->prefix .
        'iranica_warehouse_stock';

    $sql = $wpdb->prepare(
        "
        UPDATE {$table}
        SET reserved_qty = reserved_qty + %f,
            updated_at = %s
        WHERE warehouse_id = %d
          AND product_id = %d
          AND (stock_qty - reserved_qty) >= %f
        ",
        $qty,
        current_time( 'mysql', true ),
        $warehouse_id,
        $product_id,
        $qty
    );

    $affected = $wpdb->query( $sql );

    return 1 === $affected;
}

اگر ردیف به‌روزرسانی نشود، یعنی در همان لحظه موجودی آزاد کافی نبوده است. در این حالت الگوریتم می‌تواند انبار بعدی را امتحان کند یا سفارش را بین دو محل تقسیم کند.

مرحله ۵: تخصیص سفارش را ثبت کنید

فقط کم‌کردن Reserved کافی نیست. باید بدانیم این رزرو متعلق به کدام سفارش و کدام Line Item است تا در پرداخت، لغو و مرجوعی بتوانیم همان انبار را پیدا کنیم.

CREATE TABLE wp_iranica_order_allocations (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    order_id BIGINT UNSIGNED NOT NULL,
    order_item_id BIGINT UNSIGNED NOT NULL,
    warehouse_id BIGINT UNSIGNED NOT NULL,
    product_id BIGINT UNSIGNED NOT NULL,
    qty DECIMAL(20,4) NOT NULL,
    status VARCHAR(30) NOT NULL DEFAULT 'reserved',
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,
    PRIMARY KEY (id),
    KEY order_id (order_id),
    KEY order_item_id (order_item_id),
    KEY warehouse_id (warehouse_id),
    KEY product_id (product_id),
    KEY allocation_status (status)
) ENGINE=InnoDB;

Status می‌تواند مقادیری مثل reserved، fulfilled، released یا returned داشته باشد. این وضعیت‌ها باید با چرخه واقعی کسب‌وکار شما هماهنگ شوند.

چه زمانی موجودی فیزیکی انبار کم شود؟

در زمان Checkout فقط Reserved انبار را افزایش دهید. وقتی WooCommerce واقعاً Stock سفارش را کاهش می‌دهد، همان زمان موجودی فیزیکی Location تخصیص‌یافته را کم کنید و Reserved را آزاد کنید.

هسته WooCommerce اکشن woocommerce_reduce_order_item_stock را بعد از کاهش Stock هر آیتم اجرا می‌کند. همین نقطه برای نهایی‌کردن Allocation مناسب است:

<?php

add_action(
    'woocommerce_reduce_order_item_stock',
    function( $item, $change, $order ) {
        global $wpdb;

        if (
            ! $item instanceof
                WC_Order_Item_Product
        ) {
            return;
        }

        $allocations = $wpdb->get_results(
            $wpdb->prepare(
                "
                SELECT *
                FROM {$wpdb->prefix}iranica_order_allocations
                WHERE order_item_id = %d
                  AND status = 'reserved'
                ",
                $item->get_id()
            )
        );

        foreach ( $allocations as $row ) {
            $updated = $wpdb->query(
                $wpdb->prepare(
                    "
                    UPDATE {$wpdb->prefix}iranica_warehouse_stock
                    SET stock_qty = stock_qty - %f,
                        reserved_qty =
                            GREATEST(
                                reserved_qty - %f,
                                0
                            ),
                        updated_at = %s
                    WHERE warehouse_id = %d
                      AND product_id = %d
                      AND stock_qty >= %f
                    ",
                    $row->qty,
                    $row->qty,
                    current_time(
                        'mysql',
                        true
                    ),
                    $row->warehouse_id,
                    $row->product_id,
                    $row->qty
                )
            );

            if ( 1 !== $updated ) {
                $order->add_order_note(
                    'خطا در کاهش موجودی انبار برای تخصیص #' .
                    $row->id
                );

                continue;
            }

            $wpdb->update(
                $wpdb->prefix .
                    'iranica_order_allocations',
                array(
                    'status' => 'fulfilled',
                    'updated_at' =>
                        current_time(
                            'mysql',
                            true
                        ),
                ),
                array(
                    'id' => $row->id,
                ),
                array( '%s', '%s' ),
                array( '%d' )
            );
        }
    },
    20,
    3
);

در پروژه تولیدی بهتر است شکست کاهش Location Stock فقط با Order Note تمام نشود؛ آن را در یک Queue خطا یا Alert مدیریتی نیز ثبت کنید تا سفارش بدون انبار مشخص وارد مرحله ارسال نشود.

اگر سفارش لغو یا Failed شد چه اتفاقی می‌افتد؟

WooCommerce برای سفارش‌هایی که Stock آن‌ها قبلاً کاهش یافته، در وضعیت‌های مناسب Stock اصلی را برمی‌گرداند. برای انبار مکانی نیز باید دقیقاً همان Allocation را به همان Warehouse برگردانیم.

اکشن woocommerce_restore_order_item_stock بعد از Restore شدن موجودی یک آیتم اجرا می‌شود. بنابراین به‌جای حدس‌زدن Status، بهتر است بازیابی انبار مکانی را با رویداد واقعی Restore هماهنگ کنید.

⚠️ نکته مهم برای WooCommerce 11.x: هسته می‌تواند Stock سفارش کاهش‌یافته را هنگام رفتن سفارش به Failed نیز Restore کند. بنابراین نوشتن یک Hook مستقل که صرفاً با دیدن Failed دوباره Stock را زیاد کند، خطر افزایش دوبرابری موجودی دارد.

مرحله ۶: انتقال کالا بین دو انبار

انتقال انبار فقط «منهای تهران، بعلاوه شیراز» نیست. بهتر است سند انتقال وضعیت داشته باشد تا معلوم باشد کالا هنوز در مسیر است یا واقعاً تحویل مقصد شده است.

چرخه پیشنهادی انتقال
وضعیت اتفاق موجودی
Draft هیچ تغییری در موجودی ایجاد نمی‌شود.
In Transit کالا از موجودی قابل فروش مبدا خارج می‌شود، اما هنوز وارد مقصد نشده است.
Received موجودی مقصد افزایش می‌یابد.
Cancelled اگر قبلاً از مبدا خارج شده، طبق سیاست انتقال به مبدا برگردد.

اگر کالای در حال انتقال را قابل فروش نمی‌دانید، هنگام In Transit مجموع Stock کل WooCommerce نیز باید کاهش پیدا کند و هنگام دریافت در مقصد دوباره افزایش یابد. اگر انتقال در همان لحظه و بدون دوره حمل انجام می‌شود، مجموع کل تغییر نمی‌کند.

انتقال باید اتمیک باشد

اگر مبدا کم شود ولی مقصد به علت خطای دیتابیس زیاد نشود، موجودی از بین می‌رود. جدول‌های اختصاصی را با InnoDB بسازید و عملیات نهایی انتقال را داخل Transaction انجام دهید.

START TRANSACTION;

-- کاهش موجودی مبدا
UPDATE wp_iranica_warehouse_stock
SET stock_qty = stock_qty - 5
WHERE warehouse_id = 1
  AND product_id = 125
  AND stock_qty - reserved_qty >= 5;

-- افزایش موجودی مقصد
UPDATE wp_iranica_warehouse_stock
SET stock_qty = stock_qty + 5
WHERE warehouse_id = 2
  AND product_id = 125;

COMMIT;

در کد واقعی قبل از Commit باید تعداد ردیف‌های تغییرکرده بررسی شود؛ اگر مبدا موجودی کافی نداشت یا مقصد پیدا نشد، Transaction باید Rollback شود.

مرجوعی به کدام انبار برگردد؟

وقتی یک آیتم Refund یا Restock می‌شود، همیشه لازم نیست به همان انبار اولیه برگردد. بعضی کسب‌وکارها یک انبار مجزا برای مرجوعی دارند تا کالا قبل از کنترل کیفیت دوباره قابل فروش نشود.

سه سیاست متداول دارید: برگشت به انبار اولیه سفارش، برگشت به نزدیک‌ترین انبار یا ورود به «انبار مرجوعی/قرنطینه». اگر کالا نیاز به بررسی دارد، گزینه سوم امن‌تر است؛ چون موجودی فیزیکی برگشته ولی هنوز نباید وارد Stock قابل فروش شود.

موجودی چند انبار را چگونه در سایت نمایش دهیم؟

لازم نیست همیشه نام انبار را به مشتری نشان دهید. سه مدل رایج وجود دارد:

🔹 پنهان: مشتری فقط می‌بیند کالا موجود است و انتخاب انبار کاملاً پشت‌صحنه انجام می‌شود.

🔹 نمایش شهر: مشتری می‌بیند کالا در تهران یا شیراز موجود است، اما سیستم انبار را انتخاب می‌کند.

🔹 انتخاب توسط مشتری: برای Pickup یا تحویل حضوری، مشتری Location را خودش انتخاب می‌کند.

برای فروش عادی اینترنتی، پنهان‌بودن Location معمولاً تجربه ساده‌تری می‌دهد. انتخاب انبار توسط مشتری زمانی معنا دارد که محل تحویل یا قیمت/زمان ارسال واقعاً متفاوت باشد.

چند انبار یعنی پردازش بیشتر روی فروشگاه

تخصیص Location، رزرو، انتقال، گزارش انبار و Sync با ERP باعث Query و Jobهای بیشتری می‌شود. اگر فروشگاه سفارش زیادی دارد، هنگام انتخاب میزبانی باید عملکرد دیتابیس، PHP Workerها و اجرای Cron/Action Scheduler را نیز در نظر بگیرید.

تماس با پشتیبانی ایرانیکاسرور: 021-91302467

چند انبار و ERP؛ کدام سیستم مرجع باشد؟

اگر نرم‌افزار حسابداری، WMS یا ERP نیز موجودی را مدیریت می‌کند، از همان ابتدا یک Source of Truth تعیین کنید. اگر ERP مرجع اصلی است، WooCommerce نباید مستقل موجودی Locationها را تغییر دهد و سپس تلاش کند اختلاف را با ERP حل کند.

مدل مناسب می‌تواند این باشد: ERP موجودی هر انبار را نگه می‌دارد، اتصال API آن را به جدول Location Stock می‌آورد و مجموع قابل فروش به WooCommerce منتقل می‌شود. سفارش‌های WooCommerce نیز Allocation را به ERP برمی‌گردانند.

📌 وقتی انبارداری به حسابداری وصل می‌شود

اگر هدف شما فقط Stock فروشگاه نیست و می‌خواهید ورود و خروج انبار به سیستم مالی هم متصل شود، مقاله معرفی نرم‌افزار حسابداری حسابک دید بهتری درباره ارتباط انبار، فروش و حسابداری می‌دهد.

اگر فروشگاه بزرگ است، Sync را در Queue اجرا کنید

به‌روزرسانی صدها SKU از ERP یا CSV نباید در یک درخواست مرورگر انجام شود. پردازش را به بسته‌های کوچک تقسیم و با Action Scheduler اجرا کنید تا شکست یک محصول کل Import را متوقف نکند.

هر Job باید Idempotent باشد؛ یعنی اگر دوباره اجرا شد، یک انتقال یا ورود موجودی را دو بار ثبت نکند. برای این کار Event ID یا External Reference دریافت‌شده از سیستم مبدا را ذخیره و Unique کنید.

چه زمانی توسعه اختصاصی مناسب نیست؟

اگر فقط دو انبار دارید و نیازتان محدود به واردکردن تعداد هر Location، انتخاب انبار و گزارش ساده است، توسعه کامل اختصاصی می‌تواند هزینه نگهداری غیرضروری ایجاد کند. افزونه‌های چندموجودی موجود در Marketplace WooCommerce امکاناتی مانند Location، اولویت انبار، موجودی هر محل، CSV و بعضاً انتخاب نزدیک‌ترین محل را آماده ارائه می‌کنند.

توسعه اختصاصی زمانی ارزش بیشتری دارد که قوانین تخصیص خاص، ERP داخلی، چند شرکت، مسیر انتقال، انبار قرنطینه، SLA ارسال یا گزارش مالی اختصاصی دارید.

خطاهای رایج در چندانباره‌کردن WooCommerce

برای هر انبار یک Custom Field روی محصول می‌سازیم

برای دو فیلد آزمایشی شاید جواب بدهد، اما با افزایش انبار، Variation، انتقال و گزارش، Post Meta به مدل پیچیده و سخت‌گزارش تبدیل می‌شود. جدول اختصاصی ساختار مناسب‌تری دارد.

Stock کل را مستقل از Locationها دستی تغییر می‌دهیم

اگر مجموع Locationها ۲۴ باشد ولی WooCommerce عدد ۳۱ را نشان دهد، سیستم دو حقیقت متفاوت دارد. Stock کل باید از منبع مشخص و قابل بازسازی تولید شود.

رزرو مکانی را بدون قفل هم‌زمانی می‌نویسیم

Read سپس Update جداگانه در سفارش‌های هم‌زمان می‌تواند Overselling یک Location بسازد. رزرو را با Update شرطی یا Transaction امن انجام دهید.

انتقال در راه را داخل هر دو انبار حساب می‌کنیم

کالایی که از مبدا خارج شده ولی به مقصد نرسیده نباید هم‌زمان در هر دو محل قابل فروش باشد. وضعیت In Transit باید رفتار روشنی داشته باشد.

در Cancel و Failed موجودی را دوباره زیاد می‌کنیم

WooCommerce خودش Restore Stock دارد. سیستم مکانی باید به رویداد واقعی Restore متصل شود، نه اینکه صرفاً با تغییر Status دوباره Stock را زیاد کند.

چک‌لیست تست سیستم چند انبار

قبل از فعال‌سازی روی فروشگاه اصلی
سناریو نتیجه درست
یک کالا در سه انبار مجموع Stock WooCommerce برابر مجموع فیزیکی Locationهای فعال باشد.
دو سفارش هم‌زمان یک واحد موجودی مکانی به دو سفارش تخصیص داده نشود.
پرداخت موفق Stock کل یک بار و Location تخصیص‌یافته همان مقدار کاهش یابد.
لغو سفارش موجودی دقیقاً به Location قبلی برگردد.
Split Shipment مجموع Allocationها برابر Quantity آیتم سفارش باشد.
انتقال در راه کالا هم‌زمان در مبدا و مقصد قابل فروش نباشد.
مرجوعی سیاست انبار برگشت مشخص و قابل Audit باشد.
Sync ERP تکراری اجرای دوباره Event باعث دو برابر شدن Stock نشود.

پرسش‌های متداول

آیا WooCommerce به‌صورت پیش‌فرض چند انبار را مدیریت می‌کند؟

هسته WooCommerce یک Stock Quantity اصلی برای محصول یا Variation مدیریت می‌کند. برای موجودی جداگانه هر Location به لایه افزونه یا توسعه اختصاصی نیاز دارید.

Stock اصلی WooCommerce در سیستم چندانباره چه باشد؟

در معماری این مقاله، Stock اصلی برابر مجموع موجودی فیزیکی قابل فروش انبارهای فعال است و جزئیات هر Location جدا نگهداری می‌شود.

آیا مشتری باید انبار را انتخاب کند؟

نه لزوماً. برای ارسال عادی بهتر است سیستم خودش براساس اولویت، مقصد یا موجودی Location را انتخاب کند. انتخاب مشتری بیشتر برای Pickup یا شرایطی که محل تحویل اهمیت مستقیم دارد مناسب است.

اگر یک انبار به‌تنهایی Quantity سفارش را ندارد چه کنیم؟

دو انتخاب دارید: سفارش را رد کنید یا Split Shipment را فعال کنید و Quantity را بین چند Location تقسیم کنید. تصمیم باید براساس هزینه حمل و سیاست عملیات باشد.

آیا انتقال بین دو انبار باید Stock کل WooCommerce را تغییر دهد؟

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

برای چند انبار افزونه آماده بهتر است یا توسعه اختصاصی؟

برای نیاز ساده، افزونه آماده معمولاً سریع‌تر و کم‌هزینه‌تر است. توسعه اختصاصی زمانی منطقی‌تر است که قوانین تخصیص، ERP، انتقال، چند شرکت یا فرایند مرجوعی شما با افزونه‌های آماده هماهنگ نباشد.

منابع رسمی این آموزش

🔹 مستندات Inventory محصول در WooCommerce — مرجع Stock Quantity، Backorder و Low Stock در محصول و Variation.

🔹 WooCommerce Stock Functions — مرجع رسمی کاهش، افزایش، Restore و Hookهای موجودی سفارش.

🔹 مستندات Multi Inventory Management در WooCommerce Marketplace — نمونه عملی از مدل Location، Priority، موجودی هر محل و Total Stock.

🔹 مستندات Multi Locations Inventory Management — نمونه قابلیت‌هایی مثل Supplier، Location Priority، Stock History و مدیریت چند Location.

🔹 WooCommerce 11.2.1 Release Notes — مرجع نسخه پایدار بررسی‌شده هنگام نگارش مقاله.

جمع‌بندی

برای مدیریت چند انبار در WooCommerce، بهتر است Stock اصلی ووکامرس را حذف یا دور نزنید. موجودی هر Location را در ساختار مستقل نگه دارید، Stock کل را از مجموع انبارهای فعال بسازید، هنگام Checkout فقط Location را رزرو کنید و کاهش فیزیکی انبار را با رویداد واقعی کاهش Stock ووکامرس هماهنگ کنید. انتقال کالا باید وضعیت داشته باشد، Cancel و Failed باید به همان Allocation قبلی برگردند و در فروشگاه‌های متصل به ERP فقط یک سیستم باید مرجع اصلی موجودی باشد.

برای Sync چند انبار یا اتصال ERP به زیرساخت جدا نیاز دارید؟

اگر همگام‌سازی موجودی، Queue، API یا Jobهای دوره‌ای فشار زیادی روی هاست فروشگاه ایجاد می‌کنند، می‌توان سرویس واسط یا پردازش پس‌زمینه را روی VPS جدا اجرا کرد تا Checkout فروشگاه از پردازش‌های سنگین مستقل‌تر بماند.

تماس با پشتیبانی ایرانیکاسرور: 021-91302467

اشتراک‌گذاری مقاله
گفت‌وگو درباره آموزش

دیدگاه‌ها (۰)

هنوز دیدگاهی ثبت نشده است.

دیدگاه یا سؤال خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *