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

ساخت صندوق فروش حضوری برای ووکامرس؛ اتصال POS به سایت و موجودی آنلاین

POS یا «صندوق فروش» همان بخشی است که فروش حضوری فروشگاه را ثبت می‌کند؛ یعنی صندوقدار کالا را با جست‌وجو یا بارکد پیدا می‌کند، به سبد اضافه می‌کند، مبلغ را می‌گیرد، رسید صادر می‌کند…

ساخت صندوق فروش حضوری برای ووکامرس؛ اتصال POS به سایت و موجودی آنلاین
خلاصه سریع این آموزش

POS یا «صندوق فروش» همان بخشی است که فروش حضوری فروشگاه را ثبت می‌کند؛ یعنی صندوقدار کالا را با جست‌وجو یا بارکد پیدا می‌کند، به سبد اضافه می‌کند، مبلغ را…

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

POS یا «صندوق فروش» همان بخشی است که فروش حضوری فروشگاه را ثبت می‌کند؛ یعنی صندوقدار کالا را با جست‌وجو یا بارکد پیدا می‌کند، به سبد اضافه می‌کند، مبلغ را می‌گیرد، رسید صادر می‌کند و در پایان موجودی همان کالا در WooCommerce هم به‌روز می‌شود. اگر فروشگاه آنلاین و فروشگاه فیزیکی هر دو از یک موجودی استفاده می‌کنند، داشتن POS متصل به WooCommerce جلوی ثبت دوباره فروش و اختلاف موجودی را می‌گیرد.

در این آموزش یک POS تحت وب می‌سازیم که روی تبلت، لپ‌تاپ یا کامپیوتر فروشگاه باز شود، کالا را با SKU یا بارکد پیدا کند، سبد فروش حضوری بسازد، سفارش WooCommerce ایجاد کند و بعد از قطعی‌شدن پرداخت موجودی را با منطق خود WooCommerce کاهش دهد. نسخه پایه را آنلاین می‌سازیم و در ادامه توضیح می‌دهیم برای حالت آفلاین، چند صندوق و اتصال به کارت‌خوان چه معماری‌ای لازم است.

📌 خروجی نهایی: یک رابط صندوق فروش دارید که محصول را می‌خواند، سبد می‌سازد، پرداخت نقدی یا پرداخت تأییدشده را ثبت می‌کند، سفارش را با مبدا POS داخل WooCommerce ذخیره می‌کند و کاهش Stock را به خود WooCommerce می‌سپارد تا سفارش حضوری و آنلاین از یک موجودی استفاده کنند.

فهرست مطالب

قبل از ساخت POS اختصاصی، گزینه رسمی WooCommerce را بشناسید

در نسخه‌های جدید WooCommerce، بخش Point of Sale دیگر فقط یک قابلیت آزمایشی نیست. از WooCommerce 11.0 تب POS در تنظیمات برای همه فروشگاه‌ها دیده می‌شود و Woo Mobile App نیز حالت صندوق فروش دارد که روی دستگاه‌های پشتیبانی‌شده می‌تواند فروش حضوری را با فروشگاه WooCommerce همگام کند.

اگر کشور، ارز، دستگاه و روش پرداخت شما در فهرست پشتیبانی Woo قرار دارد و امکانات استاندارد برایتان کافی است، استفاده از POS رسمی می‌تواند سریع‌تر باشد. اما اگر کارت‌خوان محلی، بارکد اختصاصی، چاپ رسید سفارشی، چند انبار، قوانین قیمت‌گذاری خاص، نقش صندوقدار یا اتصال به ERP دارید، POS اختصاصی انعطاف بیشتری می‌دهد.

کدام مسیر مناسب‌تر است؟
نیاز POS رسمی Woo POS اختصاصی
فروش حضوری ساده مناسب ممکن است بیش از نیاز باشد
پرداخت محلی اختصاصی وابسته به پشتیبانی رسمی قابل پیاده‌سازی با Gateway یا ترمینال محلی
چاپ رسید سفارشی در چارچوب قابلیت‌های موجود قابل طراحی کامل
چند انبار نیازمند بررسی افزونه و Workflow قابل اتصال به سیستم چندانباره اختصاصی
قوانین قیمت و تخفیف خاص محدود به امکانات موجود قابل کنترل از Backend

معماری امن POS اختصاصی برای WooCommerce

مهم‌ترین اصل امنیتی این است که Consumer Key و Consumer Secret ووکامرس داخل JavaScript مرورگر قرار نگیرند. هر کسی که DevTools مرورگر را باز کند می‌تواند چنین کلیدی را ببیند و اگر کلید Write داشته باشد، به سفارش‌ها و محصولات فروشگاه دسترسی پیدا کند.

برای POS دو معماری مناسب داریم:

🔹 افزونه داخل WordPress: رابط POS از همان دامنه فروشگاه باز می‌شود و Endpoint اختصاصی با نقش صندوقدار کار می‌کند. این مسیر برای یک فروشگاه معمولاً ساده‌تر است.

🔹 Backend واسط: رابط POS روی دامنه یا برنامه دیگری است، اما درخواست‌ها ابتدا به Backend امن شما می‌روند و آن Backend با REST API ووکامرس صحبت می‌کند. کلید WooCommerce فقط سمت سرور می‌ماند.

در این مقاله نمونه اصلی را به‌صورت افزونه WordPress می‌سازیم؛ چون مستقیم به APIهای WooCommerce دسترسی دارد، با HPOS سازگارتر است و برای ساخت سفارش نیازی به افشای REST API Key در مرورگر ندارد.

⚠️ نکته امنیتی: اگر POS روی یک دامنه جدا اجرا می‌شود، کلید WooCommerce را در فایل JavaScript، LocalStorage یا اپ موبایل خام قرار ندهید. کلید باید فقط در Backend امن و ترجیحاً در Environment Variable نگهداری شود.

📌 پیش از توسعه فروشگاه بکاپ داشته باشید

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

مرحله ۱: نقش صندوقدار بسازید

صندوقدار نباید Administrator باشد. یک Capability جدا با نام use_iranica_pos می‌سازیم تا فقط کاربران مجاز بتوانند Endpoint صندوق را اجرا کنند.

<?php

register_activation_hook(
    __FILE__,
    function() {
        add_role(
            'iranica_pos_cashier',
            'صندوقدار POS',
            array(
                'read'            => true,
                'use_iranica_pos' => true,
            )
        );

        $manager = get_role( 'shop_manager' );

        if ( $manager ) {
            $manager->add_cap(
                'use_iranica_pos'
            );
        }

        $admin = get_role( 'administrator' );

        if ( $admin ) {
            $admin->add_cap(
                'use_iranica_pos'
            );
        }
    }
);

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

مرحله ۲: Endpoint جست‌وجوی کالا را بسازید

ساده‌ترین راه اتصال بارکدخوان این است که بارکد محصول را با SKU یکسان کنید. بیشتر بارکدخوان‌های USB مانند کیبورد عمل می‌کنند؛ یعنی کد را تایپ و در پایان Enter ارسال می‌کنند و به API سخت‌افزاری خاصی نیاز ندارند.

Endpoint زیر محصول را با SKU پیدا می‌کند و فقط اطلاعات موردنیاز صندوق را برمی‌گرداند:

<?php

add_action(
    'rest_api_init',
    function() {
        register_rest_route(
            'iranica-pos/v1',
            '/product',
            array(
                'methods'  => 'GET',
                'callback' =>
                    'iranica_pos_get_product',
                'permission_callback' =>
                    function() {
                        return current_user_can(
                            'use_iranica_pos'
                        );
                    },
            )
        );
    }
);

function iranica_pos_get_product(
    WP_REST_Request $request
) {
    $sku = sanitize_text_field(
        (string) $request->get_param(
            'sku'
        )
    );

    if ( '' === $sku ) {
        return new WP_Error(
            'missing_sku',
            'SKU is required.',
            array( 'status' => 400 )
        );
    }

    $product_id =
        wc_get_product_id_by_sku( $sku );

    $product =
        wc_get_product( $product_id );

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

    return rest_ensure_response(
        array(
            'id'           =>
                $product->get_id(),
            'name'         =>
                $product->get_name(),
            'sku'          =>
                $product->get_sku(),
            'price'        =>
                $product->get_price(),
            'stock_status' =>
                $product->get_stock_status(),
            'stock_qty'    =>
                $product->get_stock_quantity(),
            'manage_stock' =>
                $product->managing_stock(),
        )
    );
}

اگر محصول Variable است، بهتر است SKU روی خود Variation قرار بگیرد تا بارکد دقیقاً همان رنگ، سایز یا مدل را پیدا کند.

مرحله ۳: بارکدخوان را به رابط POS وصل کنید

یک Input در رابط POS کافی است. بارکدخوان کد را وارد می‌کند و وقتی Enter رسید، محصول از Endpoint خوانده و به سبد اضافه می‌شود.

const scanner = document.querySelector(
    '#barcode'
);

scanner.addEventListener(
    'keydown',
    async (event) => {
        if (event.key !== 'Enter') {
            return;
        }

        const sku = scanner.value.trim();

        scanner.value = '';

        if (!sku) {
            return;
        }

        const response = await fetch(
            '/wp-json/iranica-pos/v1/product?sku=' +
            encodeURIComponent(sku),
            {
                credentials: 'same-origin',
                headers: {
                    'X-WP-Nonce':
                        window.iranicaPosNonce
                }
            }
        );

        if (!response.ok) {
            alert('کالا پیدا نشد');
            return;
        }

        const product =
            await response.json();

        addProductToCart(product);
    }
);

در صفحه‌ای که POS را نمایش می‌دهد، Nonce وردپرس را با wp_create_nonce(‘wp_rest’) تولید کنید و فقط برای کاربر واردشده در اختیار JavaScript قرار دهید.

مرحله ۴: فروش را به Order واقعی WooCommerce تبدیل کنید

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

در نسخه‌های جدید WooCommerce می‌توان مبدا Order را با created_via مشخص کرد. برای POS از مقدار pos-rest-api استفاده می‌کنیم تا سفارش‌های حضوری از سفارش‌های سایت قابل تفکیک باشند.

<?php

use Automattic\WooCommerce\Checkout\Helpers\ReserveStockException;

add_action(
    'rest_api_init',
    function() {
        register_rest_route(
            'iranica-pos/v1',
            '/sale',
            array(
                'methods'  => 'POST',
                'callback' =>
                    'iranica_pos_create_sale',
                'permission_callback' =>
                    function() {
                        return current_user_can(
                            'use_iranica_pos'
                        );
                    },
            )
        );
    }
);

function iranica_pos_create_sale(
    WP_REST_Request $request
) {
    $data = $request->get_json_params();

    $items = isset( $data['items'] )
        && is_array( $data['items'] )
        ? $data['items']
        : array();

    if ( empty( $items ) ) {
        return new WP_Error(
            'empty_cart',
            'Cart is empty.',
            array( 'status' => 400 )
        );
    }

    $customer_id =
        isset( $data['customer_id'] )
        ? absint( $data['customer_id'] )
        : 0;

    $payment_method =
        isset( $data['payment_method'] )
        ? sanitize_key(
            $data['payment_method']
        )
        : 'pos_cash';

    $payment_title =
        isset( $data['payment_title'] )
        ? sanitize_text_field(
            $data['payment_title']
        )
        : 'پرداخت نقدی صندوق';

    $transaction_id =
        isset( $data['transaction_id'] )
        ? sanitize_text_field(
            $data['transaction_id']
        )
        : '';

    $pos_uuid =
        isset( $data['pos_uuid'] )
        ? sanitize_text_field(
            $data['pos_uuid']
        )
        : wp_generate_uuid4();

    $order = wc_create_order(
        array(
            'customer_id' => $customer_id,
            'created_via' => 'pos-rest-api',
        )
    );

    if ( is_wp_error( $order ) ) {
        return $order;
    }

    try {
        foreach ( $items as $item ) {
            $product_id = isset(
                $item['product_id']
            )
                ? absint(
                    $item['product_id']
                )
                : 0;

            $quantity = isset(
                $item['quantity']
            )
                ? absint(
                    $item['quantity']
                )
                : 0;

            $product =
                wc_get_product(
                    $product_id
                );

            if (
                ! $product
                    instanceof WC_Product ||
                $quantity < 1
            ) {
                throw new Exception(
                    'Invalid cart item.'
                );
            }

            $order->add_product(
                $product,
                $quantity
            );
        }

        $order->set_payment_method(
            $payment_method
        );

        $order->set_payment_method_title(
            $payment_title
        );

        $order->update_meta_data(
            '_iranica_pos_uuid',
            $pos_uuid
        );

        $order->update_meta_data(
            '_iranica_pos_cashier',
            get_current_user_id()
        );

        $order->calculate_totals();
        $order->save();

        /*
         * رزرو اتمیک Stock قبل از قطعی‌کردن
         * پرداخت؛ اگر موجودی کافی نباشد،
         * WooCommerce Exception می‌دهد.
         */
        wc_reserve_stock_for_order(
            $order
        );

        /*
         * این خط فقط زمانی اجرا شود که
         * وجه واقعاً دریافت شده باشد.
         */
        $order->payment_complete(
            $transaction_id
        );

        $order->add_order_note(
            'فروش از صندوق POS ثبت شد.'
        );

        return rest_ensure_response(
            array(
                'success'      => true,
                'order_id'     =>
                    $order->get_id(),
                'order_number' =>
                    $order->get_order_number(),
                'total'        =>
                    $order->get_total(),
                'pos_uuid'     =>
                    $pos_uuid,
            )
        );

    } catch ( ReserveStockException $e ) {
        wc_release_stock_for_order(
            $order
        );

        $order->delete( true );

        return new WP_Error(
            $e->getErrorCode(),
            $e->getMessage(),
            array( 'status' => 409 )
        );

    } catch ( Throwable $e ) {
        wc_release_stock_for_order(
            $order
        );

        $order->delete( true );

        return new WP_Error(
            'pos_sale_failed',
            'ثبت فروش ناموفق بود.',
            array( 'status' => 500 )
        );
    }
}

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

⚠️ بسیار مهم: payment_complete() را قبل از دریافت واقعی وجه اجرا نکنید. اگر پرداخت کارت‌خوان رد شد ولی Order به‌عنوان Paid ثبت شود، موجودی کاهش می‌یابد و گزارش فروش اشتباه می‌شود.

پرداخت نقدی و کارت‌خوان را چطور مدیریت کنیم؟

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

شماره کارت، CVV2 یا اطلاعات حساس بانکی را داخل WooCommerce یا POS خودتان ذخیره نکنید. برای گزارش، Transaction ID یا Reference Number پرداخت کافی است.

رفتار پیشنهادی برای روش‌های پرداخت
روش چه زمانی Paid شود؟ داده‌ای که ذخیره می‌شود
نقدی بعد از دریافت وجه نام صندوق و صندوقدار
کارت‌خوان بعد از پاسخ موفق دستگاه Reference/Transaction ID
پرداخت ترکیبی وقتی کل مبلغ تسویه شد جزئیات هر سهم پرداخت در Meta یا سیستم حسابداری

مرحله ۵: رسید فروش را چاپ کنید

برای نسخه پایه لازم نیست از همان ابتدا سراغ ESC/POS و اتصال مستقیم USB بروید. یک صفحه رسید با عرض مناسب چاپگر ۸۰ میلی‌متری بسازید و از Print Dialog سیستم استفاده کنید. این روش با درایور معمول چاپگر کار می‌کند و وابستگی سخت‌افزاری کمتری دارد.

اگر می‌خواهید چاپ بدون بازشدن پنجره Print، بازکردن کشوی پول یا چاپ مستقیم Raw انجام شود، معمولاً به یک Local Print Bridge، اپ دسکتاپ یا Wrapper بومی نیاز دارید؛ چون مرورگرها عمداً دسترسی مستقیم و آزاد به همه سخت‌افزارهای سیستم نمی‌دهند.

فروش بدون مشتری یا با مشتری ثبت‌شده؟

برای مشتری گذری می‌توانید Order را با customer_id = 0 ثبت کنید. اگر مشتری عضو سایت است، جست‌وجوی شماره تلفن یا ایمیل را به POS اضافه کنید و Customer ID واقعی را روی سفارش قرار دهید تا تاریخچه خرید آنلاین و حضوری یکجا بماند.

اگر سیستم وفاداری، اعتبار مشتری یا قیمت‌گذاری عمده دارید، شناسایی Customer قبل از محاسبه نهایی سبد مهم‌تر می‌شود.

تخفیف در صندوق را چگونه پیاده کنیم؟

سه مدل رایج دارید: استفاده از Coupon خود WooCommerce، تخفیف دستی با سطح دسترسی مدیر، یا Price Rule اختصاصی. برای جلوگیری از سوءاستفاده، صندوقدار عادی نباید بتواند هر مبلغی را بدون محدودیت تخفیف دهد.

می‌توانید مثلاً تا ۵ درصد تخفیف را به صندوقدار و تخفیف بیشتر را فقط با PIN مدیر مجاز کنید. درصد دقیق باید متناسب با کسب‌وکار شما تعریف شود؛ این عدد یک مثال سیاست دسترسی است، نه توصیه عمومی.

چطور جلوی ثبت دوباره فروش را بگیریم؟

اگر اینترنت لحظه‌ای قطع شود، کاربر ممکن است دکمه «ثبت فروش» را دوباره بزند. اگر هر درخواست Order جدید بسازد، یک خرید می‌تواند دو بار وارد WooCommerce شود.

برای هر Sale یک UUID ثابت بسازید و قبل از Create Order بررسی کنید قبلاً این UUID Sync نشده باشد. در نسخه Production بهتر است UUID در یک جدول اختصاصی با Unique Index ذخیره شود.

CREATE TABLE wp_iranica_pos_sync (
    pos_uuid CHAR(36) NOT NULL,
    woo_order_id BIGINT UNSIGNED NULL,
    status VARCHAR(20) NOT NULL,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,
    PRIMARY KEY (pos_uuid),
    KEY woo_order_id (woo_order_id),
    KEY status (status)
) ENGINE=InnoDB;

اگر درخواست با UUID تکراری رسید، سرور باید همان Order قبلی را برگرداند، نه اینکه Order تازه ایجاد کند.

حالت آفلاین؛ جذاب است اما باید با احتیاط ساخته شود

برای POS می‌توان Catalog را داخل IndexedDB مرورگر Cache کرد و فروش‌های ثبت‌نشده را در Queue محلی نگه داشت تا بعد از برگشت اینترنت Sync شوند. اما مشکل اصلی آفلاین «نمایش محصول» نیست؛ مشکل این است که Stock ممکن است در همان زمان توسط سایت یا صندوق دیگری تغییر کرده باشد.

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

پیشنهاد برای کنترل ریسک Offline
وضعیت کالا رفتار پیشنهادی
موجودی بالا و تازه Sync شده می‌توان طبق سیاست فروشگاه فروش آفلاین را مجاز کرد.
Low Stock فروش آفلاین مسدود یا نیازمند تأیید مدیر باشد.
Catalog قدیمی قبل از فروش Sync اجباری شود.
چند صندوق هم‌زمان بهتر است سهم موجودی آفلاین یا Reservation مرکزی داشته باشید.

اگر چند انبار دارید، POS باید Location را هم بداند

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

اگر سیستم چندانباره اختصاصی دارید، Sale POS باید Warehouse ID را نیز همراه سفارش ثبت کند و کاهش Location Stock با همان Order هماهنگ شود.

اتصال POS به حسابداری

چون هر فروش POS یک Order واقعی WooCommerce است، اتصال حسابداری می‌تواند فروش حضوری و آنلاین را از یک منبع دریافت کند. بهتر است created_via یا Meta صندوق را ذخیره کنید تا گزارش مالی بتواند فروش حضوری را جدا کند.

📌 حسابداری فروش حضوری و آنلاین را یکپارچه کنید

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

امنیت POS را دست‌کم نگیرید

🔹 صندوقدار Administrator نباشد.

🔹 Endpointهای POS فقط برای Capability مخصوص باز باشند.

🔹 اتصال فقط از HTTPS انجام شود.

🔹 کلید REST API داخل Browser قرار نگیرد.

🔹 هر Terminal شناسه جدا داشته باشد.

🔹 Sale UUID برای جلوگیری از Duplicate اجباری باشد.

🔹 اطلاعات کارت بانکی ذخیره نشود.

🔹 تخفیف، Refund و Void سطح دسترسی جدا داشته باشند.

POS جدا از سایت اجرا شود یا روی همان هاست؟

برای یک فروشگاه کوچک، اجرای POS داخل همان WordPress ساده‌تر است. اگر چند شعبه، Queue آفلاین، Sync ERP، گزارش‌های سنگین یا چند Terminal دارید، Backend واسط روی VPS می‌تواند پردازش POS را از Frontend فروشگاه جدا کند؛ در این حالت WooCommerce همچنان منبع اصلی سفارش و محصول باقی می‌ماند.

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

تست‌هایی که قبل از استفاده واقعی باید انجام دهید

سناریوهای ضروری POS
سناریو نتیجه مورد انتظار
اسکن SKU معتبر محصول درست به سبد اضافه شود.
اسکن SKU نامعتبر هیچ آیتم اشتباهی وارد سبد نشود.
آخرین واحد کالا با دو صندوق فقط یک فروش بتواند Stock را رزرو و نهایی کند.
پرداخت ناموفق Order به‌عنوان Paid ثبت نشود.
درخواست تکراری با یک UUID Order دوم ایجاد نشود.
فروش مهمان Order با Customer ID صفر ساخته شود.
Refund بازپرداخت از Workflow خود WooCommerce انجام شود.
قطع اینترنت سبد از بین نرود و سیاست Offline مشخص باشد.

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

POS ووکامرس چیست؟

POS یک صندوق فروش حضوری است که محصولات، سفارش‌ها و موجودی را با WooCommerce هماهنگ می‌کند و اجازه می‌دهد فروش فروشگاه فیزیکی داخل همان سیستم فروش آنلاین ثبت شود.

آیا WooCommerce خودش POS دارد؟

بله. Woo Mobile App حالت POS رسمی دارد و از WooCommerce 11.0 تنظیمات POS در هسته نیز برای فروشگاه‌ها دیده می‌شود؛ اما پشتیبانی پرداخت حضوری به کشور، ارز و دستگاه وابسته است.

آیا بارکدخوان معمولی با POS تحت وب کار می‌کند؟

بیشتر بارکدخوان‌های USB در حالت Keyboard Wedge مانند کیبورد عمل می‌کنند و می‌توانند SKU را داخل Input وارد کنند. برای مدل‌های خاص باید پروتکل دستگاه بررسی شود.

آیا باید REST API Key را در JavaScript بگذاریم؟

خیر. کلید Write نباید در Browser یا اپی که کاربر می‌تواند فایل‌هایش را بخواند قرار بگیرد. از WordPress REST با Session/Nonce یا Backend واسط استفاده کنید.

POS آفلاین شدنی است؟

بله، می‌توان Catalog و Queue فروش را محلی نگه داشت، اما چون Stock ممکن است در سایت یا صندوق دیگری تغییر کند، باید برای Low Stock و چند Terminal سیاست جلوگیری از Overselling داشته باشید.

فروش POS موجودی سایت را کم می‌کند؟

اگر فروش به‌صورت Order واقعی WooCommerce ثبت و پرداخت با Workflow درست نهایی شود، کاهش Stock توسط WooCommerce انجام می‌شود و موجودی حضوری و آنلاین یکپارچه می‌ماند.

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

🔹 Woo Mobile App: Point of Sale Mode — مرجع رسمی POS موبایل WooCommerce، دستگاه‌ها و شرایط استفاده.

🔹 WooCommerce Settings Documentation — توضیح بخش POS و رفتار سفارش‌های دارای created_via: pos-rest-api.

🔹 WooCommerce REST API — مرجع رسمی API سفارش، محصول و مشتری برای Integrationهای خارجی.

🔹 Orders REST API v3 — مرجع ساخت Order، پرداخت و فیلد created_via.

🔹 WooCommerce Stock Functions — مرجع wc_reserve_stock_for_order()، Release و مدیریت Stock.

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

جمع‌بندی

برای ساخت POS ووکامرس بهتر است فروش حضوری را خارج از سیستم سفارش‌ها نگه ندارید. هر Sale باید به Order واقعی WooCommerce تبدیل شود، مبدا آن POS مشخص باشد، Stock قبل از نهایی‌شدن رزرو شود و فقط پس از دریافت واقعی پول Payment Complete اجرا شود. بارکدخوان می‌تواند با SKU کار کند، صندوقدار باید نقش محدود داشته باشد و کلیدهای API نباید داخل Browser قرار بگیرند. اگر چند صندوق، حالت آفلاین یا چند انبار دارید، Idempotency، Reservation و Sync مرکزی از بخش‌های اجباری معماری هستند.

برای اجرای Backend POS یا Sync فروشگاه زیرساخت جدا می‌خواهید؟

اگر POS چند شعبه دارد، Queue آفلاین، API حسابداری یا Sync موجودی فشار زیادی روی هاست WooCommerce ایجاد می‌کند، می‌توانید Backend واسط را روی VPS اجرا کنید و فقط Order نهایی را به WooCommerce منتقل کنید.

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

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

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

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

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

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